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

            Bug ID: 128518
           Summary: wrong code at -O1: nested function address passed
                    without a trampoline although it needs the static
                    chain since r16-3747
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jeffchen006 at gmail dot com
  Target Milestone: ---
            Target: x86_64-pc-linux-gnu

int printf(const char *, ...);

void call(void (*f)(void)) { f(); }

int main(void)
{
  __label__ o1;
  void n1(void) { goto o1; }
  void n2(void)
  {
    __label__ o2;
    int v = 0;
    void n3(void) { v = 1; n1(); goto o2; }
    n3();
  o2:;
  }
  void n4(void) { call(n2); }
  n4();
o1:
  printf("ok\n");
  return 0;
}

$ gcc -O0 t.c && ./a.out
ok
$ gcc -O1 t.c && ./a.out
Segmentation fault

Expected: ok.

Cause: n2 uses no outer variable itself. But n3, nested in n2, calls n1, and n1
jumps to a label in main. So n2 needs the static chain. The C front end marks
n2 as "no non-local context" and sets TREE_NO_TRAMPOLINE on its address, so the
goto runs with a wrong frame. In mark_decl_used (c-typeck.cc), the early return
for an already marked current function stops the marking before it reaches n2.

The same commit has a second hole: a function whose body is still being parsed
has no mark yet, so an address of it taken in its own body also gets no
trampoline. The patch fixes both and has a test for each.

First bad commit: r16-3747-gafa74d37e81.
Correct on 15.2. Wrong on 16.2 and trunk.

UBSan and ASan are clean at -O0.
gcc version 17.0.0 20261029 (experimental), r17-5747-g85867b0c935,
x86_64-pc-linux-gnu

Reply via email to