On Sun, 17 Sept 2023, 20:33 Paul Floyd via Gcc, <gcc@gcc.gnu.org> wrote:

> Hi
>
> I'm looking at a Valgrind issue. Full details here
>
> https://bugs.kde.org/show_bug.cgi?id=472329
>
> This code
>
> void foo(std::optional<int64_t> f) {
>    std::cout << (f ? *f : 0) << std::endl;
>    std::set<int64_t> test;
>    test.emplace(0);
>    auto it{test.begin()};
>    while (it != test.end()) {
>      int64_t b{*it};
> // Valgrind error on next line
>      if (f && *f != b) {
> [snip]
>
> int main() { foo(std::nullopt); }
>
> generates (using g++ 12.2 on FreeBSD 13.2 amd64)
>
>         movq    40(%rbx), %rax
> Error on next line:
>         cmpq    %r14, %rax      # f, SR.252
>         je      .L47
>         cmpb    $0, -97(%rbp)   #, %sfp
>         jne     .L69
>
> Unless I'm completely mistaken cmpq %r14, %rax is the quadword
> comparison of *f != b and cmpb  $0, -97(%rbp) is the
> std::optional::operator bool() comparison with 0. That means that g++
> has transposed the order of evaluation.
>
>
> The first cmpq/je generates a
>
> ==49599== Conditional jump or move depends on uninitialised value(s)
>
> Valgrind has machinery to detect transformations like this and to
> convert them back into bit accurate bitwise ands.
>
> However, Valgrind thinks that these transpositions can't be done when
> there are potentially trapping memory loads like *f.
>

Why would it be trapping? It's loading an int64_t, which might be
uninitialised but it can't trap.

*f on a std::optional is not like dereferencing a pointer, the int64_t
memory location is always present as part of the object.


> So who is right? Is this a safe transformation?
>
> Regards
> Paul
>

Reply via email to