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 >