Bug 42953 - bad epilogue scheduling leads to stack corruption
Summary: bad epilogue scheduling leads to stack corruption
Status: RESOLVED DUPLICATE of bug 30282
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 4.5.0
: P3 major
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-02-04 07:27 UTC by Jim Wilson
Modified: 2010-02-04 07:36 UTC (History)
7 users (show)

See Also:
Host:
Target: powerpc-eabi
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
testcase for gcc mainline (rev 156310) (122 bytes, text/plain)
2010-02-04 07:30 UTC, Jim Wilson
Details
Assembly code showing bad epilogue scheduling. (329 bytes, text/plain)
2010-02-04 07:34 UTC, Jim Wilson
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jim Wilson 2010-02-04 07:27:16 UTC
The svr4 ABI requires that r1 (SP) always be valid, so it must be restored at the end of the epilogue, after the last register restore read from the stack frame.  Unfortunately, in some cases, the PPC port is scheduling the epilogue set of r1 before some register restores.  If you take an interrupt in between the r1 set and a register restore, and the interrupt handler uses the process stack, the interrupt handler may overwrite saved registers before they can be restored.  This causes difficult to debug failures.

I can reproduce the failure with -O2 -fno-omit-frame-pointer.  I don't know if the problem can be triggered with other optimization options.

The PPC port tries to prevent the r1 set from being moved before register restores by emitting a stack_tie instruction.  This uses a BLKmode read from the stack frame, which in theory should conflict with the register reads and the set of r1.  But this fails because of how reg_base_value works in alias.c.

The PPC port is using a temp register r11 in the epilogue.  In my testcase, r11 is set in the function body to the address of a variable in data.  The code that sets reg_base_value, in init_alias_analysis in alias.c, deliberately ignores instructions in the prologue and epilogue.  Thus it sees only one store to r11, and decides that r11 must hold a data variable address everywhere in the function.  When we check stack reads (using r11) against the stack_tie insn (using r1), alias analysis decides that they can't conflict because r1 points to the stack and r11 points to data.  Thus incorrect insn scheduling occurs.

This seems to be a flaw in alias analysis.  If we aren't going to count prologue/epilogue insns when computing reg_base_value, then we should not use reg_base_value when disambiguating insns in the prologue/epilogue.  Unfortunately, the interface to alias is passing in only MEMs, not insns, so we can't easily tell when we have a prologue/epilogue MEM.

A possible simple way to solve the problem is to use a stricter stack_tie insn.  I noticed that the ARM port has one that uses (mem:BLK (scratch)).  If I hack this into the rs6000 port, then this problem goes away.  Testing for this is one of the first things that write_dependence_p does, so this prevents any possible reg_base_value confusion.

This only fails if I get a symbol address into r11, and r11 is only set once, so it is a bit tricky to reproduce with small examples.  I do have a testcase that works with gcc mainline which I will attach.
Comment 1 Jim Wilson 2010-02-04 07:30:08 UTC
Created attachment 19801 [details]
testcase for gcc mainline (rev 156310)

GCC generates incorrect epilogue code for this testcase with -O2 -fno-omit-frame-pointer.
Comment 2 Jim Wilson 2010-02-04 07:34:53 UTC
Created attachment 19802 [details]
Assembly code showing bad epilogue scheduling.

This was generated with -O2 -fno-omit-frame-pointer.
Comment 3 Andrew Pinski 2010-02-04 07:36:41 UTC

*** This bug has been marked as a duplicate of 30282 ***