Bug 57147

Summary: [4.9 Regression]: setjmp call and if body wrongly elided (function runs off early end)
Product: gcc Reporter: roland
Component: middle-endAssignee: 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

Description roland 2013-05-02 17:14:26 UTC
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
Comment 1 roland 2013-05-02 17:31:44 UTC
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.
Comment 2 Richard Biener 2013-05-03 09:08:31 UTC
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.
Comment 3 Richard Biener 2013-05-03 09:24:45 UTC
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);
}
Comment 4 Richard Biener 2013-05-03 09:46:45 UTC
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.
Comment 5 Richard Biener 2013-05-03 09:57:17 UTC
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 ...
Comment 6 Richard Biener 2013-05-06 11:47:02 UTC
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