Summary: | [4.9 Regression]: setjmp call and if body wrongly elided (function runs off early end) | ||
---|---|---|---|
Product: | gcc | Reporter: | roland |
Component: | middle-end | Assignee: | Richard Biener <rguenth> |
Status: | RESOLVED FIXED | ||
Severity: | normal | CC: | rguenther |
Priority: | P3 | ||
Version: | 4.9.0 | ||
Target Milestone: | 4.9.0 | ||
Host: | Target: | arm-linux-gnueabi | |
Build: | Known to work: | ||
Known to fail: | Last reconfirmed: | 2013-05-03 00:00:00 | |
Bug Depends on: | |||
Bug Blocks: | 56982 | ||
Attachments: | preprocessed source |
Bisected to r198096: 2013-04-19 Richard Biener <rguenther@suse.de> PR tree-optimization/56982 * builtins.def (BUILT_IN_LONGJMP): longjmp is not a leaf function. * gimplify.c (gimplify_call_expr): Notice special calls. (gimplify_modify_expr): Likewise. * tree-cfg.c (make_abnormal_goto_edges): Handle setjmp-like abnormal control flow receivers. (call_can_make_abnormal_goto): Handle cfun->calls_setjmp in the same way as cfun->has_nonlocal_labels. (gimple_purge_dead_abnormal_call_edges): Likewise. (stmt_starts_bb_p): Make setjmp-like abnormal control flow receivers start a basic-block. * gcc.c-torture/execute/pr56982.c: New testcase. Confirmed also on x86_64: TestSyscall: .LFB38: .cfi_startproc pushl %edi .cfi_def_cfa_offset 8 .cfi_offset 7, -8 movl $g_expected_regs, %edi pushl %esi .cfi_def_cfa_offset 12 .cfi_offset 6, -12 subl $65636, %esp .cfi_def_cfa_offset 65648 leal 28(%esp), %esi movl %esi, (%esp) movl $0, 4(%esp) call RegsFillTestValues leal 65632(%esp), %eax movl %esi, (%esp) movl %eax, 80(%esp) movl $ContinueAfterSyscall, 88(%esp) call RegsApplySandboxConstraints movl $17, %ecx rep movsl movl $g_expected_regs, (%esp) call RegsUnsetNonCalleeSavedRegisters movl g_expected_regs+60, %eax movl %eax, g_expected_regs+4 movl g_expected_regs+52, %eax movl %eax, g_expected_regs .cfi_endproc .LFE38: .size TestSyscall, .-TestSyscall .p2align 4,,15 It's because we have <bb 4>: g_expected_regs = call_regs; RegsUnsetNonCalleeSavedRegisters (&g_expected_regs); <bb 5>: _22 = g_expected_regs.prog_ctr; g_expected_regs.r1 = _22; _23 = g_expected_regs.stack_ptr; g_expected_regs.r0 = _23; __builtin_unreachable (); which appears first in t.i.034t.local-pure-const1. Weird. Reduced testcase, miscompiles at -O. struct __jmp_buf_tag {}; typedef struct __jmp_buf_tag jmp_buf[1]; extern int _setjmp (struct __jmp_buf_tag __env[1]); jmp_buf g_return_jmp_buf; void SetNaClSwitchExpectations(void) { } void TestSyscall(void) { SetNaClSwitchExpectations(); _setjmp (g_return_jmp_buf); } It's fixup_cfg that removes the abnormal edge after ipa-pure-const figures that SetNaClSwitchExpectations () is const. And it's gimple_purge_dead_abnormal_call_edges that removes the abnormal edge despite it being fallthru as well. That results in the CFG to end in a dead point here and things go downhill. A similar testcase is for not 'const' but 'noreturn' discovery which should end up purging the fallthru edge. struct __jmp_buf_tag {}; typedef struct __jmp_buf_tag jmp_buf[1]; extern int _setjmp (struct __jmp_buf_tag __env[1]); jmp_buf g_return_jmp_buf; void SetNaClSwitchExpectations (void) { __builtin_longjmp (g_return_jmp_buf, 1); } void TestSyscall(void) { SetNaClSwitchExpectations(); _setjmp (g_return_jmp_buf); } which triggers a similar bug in remove_fallthru_edge ... Author: rguenth Date: Mon May 6 11:27:29 2013 New Revision: 198625 URL: http://gcc.gnu.org/viewcvs?rev=198625&root=gcc&view=rev Log: 2013-05-06 Richard Biener <rguenther@suse.de> PR middle-end/57147 * tree-cfg.c (gimple_purge_dead_abnormal_call_edges): If the edge is also fallthru, preserve it and just clear the abnormal flag. * tree-cfgcleanup.c (remove_fallthru_edge): If the edge is also complex, preserve that and just clear the fallthru flag. * tree-inline.c (update_ssa_across_abnormal_edges): Also update virtual operands. * gcc.dg/torture/pr57147-1.c: New testcase. * gcc.dg/torture/pr57147-2.c: Likewise. * gcc.dg/torture/pr57147-3.c: Likewise. Added: trunk/gcc/testsuite/gcc.dg/torture/pr57147-1.c trunk/gcc/testsuite/gcc.dg/torture/pr57147-2.c trunk/gcc/testsuite/gcc.dg/torture/pr57147-3.c Modified: trunk/gcc/ChangeLog trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-cfg.c trunk/gcc/tree-cfgcleanup.c trunk/gcc/tree-inline.c |
Created attachment 30006 [details] preprocessed source This is with trunk@198549. It's a regression from gcc-4_8-branch@198420. Preprocessed source attached. Configured as: --target=arm-linux-gnueabi --with-arch=armv7-a Command line below. This example is not expected to be usable on an arm-linux-gnueabi system, but the problem is easily seen by examining the assembly. In the function TestSyscall, a good compilation calls _setjmp, returns normally on a nonzero result, and ends in an __assert_fail call (a noreturn function, so no epilogue/return after the call) on a zero result. In a bad compilation, the function just ends where the _setjmp call should be, no epilogue, no return (so execution just runs into the following function). gcc/cc1 -v -fpreprocessed syscall_return_regs_test.i -quiet -dumpbase syscall_return_regs_test.c -mtls-dialect=gnu -auxbase-strip scons-out/nacl_irt_test-arm-glibc/obj/tests/syscall_return_regs/syscall_return_regs_test.o -g -O2 -Wstrict-prototypes -Wall -Wundef -Wpedantic -Werror -Wno-variadic-macros -Wno-unused-local-typedefs -std=gnu99 -version -fomit-frame-pointer -fdiagnostics-show-option -o syscall_return_regs_test.s GNU C (GCC) version 4.9.0 20130502 (experimental) (arm-linux-gnueabi) compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 ignoring nonexistent directory "/usr/local/google/home/mcgrathr/gnu/build/inst/lib/gcc/arm-linux-gnueabi/4.9.0/include" ignoring nonexistent directory "/usr/local/google/home/mcgrathr/gnu/build/inst/lib/gcc/arm-linux-gnueabi/4.9.0/include-fixed" ignoring nonexistent directory "/usr/local/google/home/mcgrathr/gnu/build/inst/arm-linux-gnueabi/include" #include "..." search starts here: #include <...> search starts here: /usr/local/google/home/mcgrathr/gnu/build/inst/arm-linux-gnueabi/sys-include End of search list. GNU C (GCC) version 4.9.0 20130502 (experimental) (arm-linux-gnueabi) compiled by GNU C version 4.6.3, GMP version 5.0.2, MPFR version 3.1.0-p3, MPC version 0.9 GGC heuristics: --param ggc-min-expand=30 --param ggc-min-heapsize=4096 Compiler executable checksum: e560f858071b4c04ef52cbbad3e21d4b