https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84414

            Bug ID: 84414
           Summary: miscompile due to assuming that object returned by
                    value cannot alias its own member pointer values
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: richard-gccbugzilla at metafoo dot co.uk
                CC: timshen at gcc dot gnu.org
  Target Milestone: ---

GCC (all versions) miscompiles this code:


struct A {
  A *children;
  long long arr[100];

  A() : children() {}
  A(int) : children(this) {}
};

__attribute__((noinline))
A Foo() {
  return A(0);
}

A x[3] = {};

void Bar(int n) {
  A a = Foo();
  for (int i = 0; i < n; i++) {
    a.children[i].children = x;
  }
}

int main() {
    Bar(3);
    return x[0].children || !x[1].children || !x[2].children;
}


A correct compilation must return 0 from main, but GCC at -O2 returns 1. The
reason is that it fails to reload 'a.children' on each iteration of the loop in
'Bar', reasoning (incorrectly) that the store to 'a.children[i].children'
cannot alias 'a.children' because 'a' has not escaped.

The above code has defined behavior in C++17, where the 'guaranteed copy
elision' rules mean that the 'this' pointer inside the A::A(int) constructor
points to the 'a' object inside 'Bar'. But since GCC chooses to perform copy
elision on this code in all language modes (and always has done so), and the
fact that it performed copy-elision is observable, this is not a C++17-specific
bug. (The same miscompile can also be observed via NRVO.)

Reply via email to