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

            Bug ID: 128660
           Summary: [14/15/16/17 Regression] wrong code: after an inlined
                    y = g () throws and the exception is caught, y has
                    been partly overwritten
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: lzy20000419 at outlook dot com
  Target Milestone: ---

Fails with trunk (gcc 17.0.0 20261111, a2a11abfad35) and with 10.1.0 through
16.2.0; 9.5.0 works.
Target: x86_64-pc-linux-gnu (also -m32).

    struct S { long a, b, c, d; };
    int k;
    __attribute__((noinline)) long f (long v) { if (k) throw 1; return v; }
    static inline S g (long v) { return S{v, f (v), v, v}; }
    int main ()
    {
      S y = { 1, 2, 3, 4 };
      k = 1;
      try { y = g (9); } catch (int) {}
      if (y.a != 1)
        __builtin_abort ();
      return 0;
    }

    g++ -O1 t.C && ./a.out

Observed: abort, y.a is 9. Expected: exit 0. f throws before the assignment to
y completes, so y.a must still be 1.
-O2, -O3 and -Og fail too. -O0 and -O1 -fno-inline work.

Godbolt (trunk, -O1 vs -O1 -fno-inline): https://godbolt.org/z/T36doEdf7

After einline:

      y.a = 9;
      _23 = f (9);        <- throws to the handler in main
      y.b = _23;  y.c = 9;  y.d = 9;

declare_return_variable (tree-inline.cc) reuses MODIFY_DEST as the return
variable when it is an automatic, non-addressable decl. It does not check
whether the call can throw to a handler in the caller, where the old value of
MODIFY_DEST is still live. 9.5 still used a temporary here.

Related: PR128312 is the same symptom for a call that is not inlined, through
return slot optimization in tree-nrv.cc. A fix in dest_safe_for_nrv_p would not
cover this case, which is created by the inliner.

Possible fix: in declare_return_variable, do not reuse MODIFY_DEST when
stmt_can_throw_internal (cfun, id->call_stmt).

Disclaimer: This test case was found with LLM-assisted targeted testing, and
the report was written with LLM assistance.
  • [Bug tree-optimization/128660]... lzy20000419 at outlook dot com via Gcc-bugs

Reply via email to