> cat bug.cc #include <vector> #include <memory> struct Foo { virtual void f() {} }; int main(int argc, char**) { std::auto_ptr<Foo> foo; if (argc) { foo.reset(new Foo()); } else { std::vector<int> v; } Foo* p = foo.release(); p->f(); } > g++ -O bug.cc > a.out Segmentation fault (core dumped) I'm using SVN revision 128838 on linux-x86_64. Without -O or with g++ version 4.2.1 this program works correctly.
I can't reproduce...
Could you please attach preprocessed source (.ii file ) and assembly output (.s) (use -save-temps option to generate them)
Created attachment 14257 [details] preprocessed source (reduced)
Created attachment 14258 [details] assembly output (for reduced bug.ii)
Confirmed. The reduced testcase gets optimized to <bb 3>: D.2145 = operator new (8); <bb 4>: ((struct Foo *) D.2145)->_vptr.Foo = &_ZTV3Foo[2]; <bb 5>: D.2147 ={v} 0B->_vptr.Foo; OBJ_TYPE_REF(*D.2147;0B->0) (0B); where dereferencing NULL obviously is bogus. After 038t.sdse2 everything looks ok: <bb 4>: D.2124_3 = (struct Foo *) D.2145_2; D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2]; goto <bb 6>; <bb 5>: deallocate (&v, 0B); <bb 6>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.2124_3(4)> foo$ptr_19(ab) = 0B; D.2147_6 = foo$ptr_16->_vptr.Foo; D.2148_7 = *D.2147_6; but after apply inline it's wrong!? <bb 3>: D.2145_2 = operator new (8); <bb 4>: D.2124_3 = (struct Foo *) D.2145_2; D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2]; <bb 5>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)> foo$ptr_19(ab) = 0B; D.2147_6 = foo$ptr_19(ab)->_vptr.Foo; D.2148_7 = *D.2147_6; OBJ_TYPE_REF(D.2148_7;foo$ptr_19(ab)->0) (foo$ptr_19(ab)); goto <bb 7>;
I can see now from the reduced testcase that the library uses mt_alloc, not the default allocator. Next time, just say it... ;)
After inlining deallocate into main we end up with: int main(int, char**) (argc, D.2111) { static struct __pool pool; static struct __pool pool; int * p; struct Foo * foo$ptr; struct Foo * D.2185; struct Foo * D.2182; int save_filt.2; void * save_eptr.1; struct vector v; int (*__vtbl_ptr_type) (void) D.2148; int (*__vtbl_ptr_type) (void) * D.2147; void * D.2145; struct Foo * D.2124; <bb 2>: foo$ptr_18(ab) = 0B; if (argc_1(D) != 0) goto <bb 3>; else goto <bb 5>; <bb 3>: D.2145_2 = operator new (8); <bb 4>: D.2124_3 = (struct Foo *) D.2145_2; D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2]; goto <bb 10>; <bb 5>: <bb 6>: if (0) goto <bb 7>; else goto <bb 8>; <bb 7>: _M_reclaim_block (&pool, 0B, 0); <bb 8>: <bb 9>: <bb 10>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(9), D.2124_3(4)> foo$ptr_19(ab) = 0B; D.2147_6 = foo$ptr_16->_vptr.Foo; D.2148_7 = *D.2147_6; OBJ_TYPE_REF(D.2148_7;foo$ptr_16->0) (foo$ptr_16); goto <bb 12>; # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), (7), foo$ptr_19(ab)(10)> <L3>:; save_filt.2_10 = <<<filter object>>>; save_eptr.1_11 = <<<exception object>>>; D.2182_13 = foo$ptr_17(ab); operator delete (D.2182_13); <<<exception object>>> = save_eptr.1_11; <<<filter object>>> = save_filt.2_10; resx 1; <bb 12>: D.2185_14 = foo$ptr_19(ab); operator delete (D.2185_14); return 0; } after cleanup_cfg it still looks sane: int main(int, char**) (argc, D.2111) { static struct __pool pool; static struct __pool pool; int * p; struct Foo * foo$ptr; struct Foo * D.2185; struct Foo * D.2182; int save_filt.2; void * save_eptr.1; struct vector v; int (*__vtbl_ptr_type) (void) D.2148; int (*__vtbl_ptr_type) (void) * D.2147; void * D.2145; struct Foo * D.2124; <bb 2>: foo$ptr_18(ab) = 0B; if (argc_1(D) != 0) goto <bb 3>; else goto <bb 5>; <bb 3>: D.2145_2 = operator new (8); <bb 4>: D.2124_3 = (struct Foo *) D.2145_2; D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2]; <bb 5>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)> foo$ptr_19(ab) = 0B; D.2147_6 = foo$ptr_16->_vptr.Foo; D.2148_7 = *D.2147_6; OBJ_TYPE_REF(D.2148_7;foo$ptr_16->0) (foo$ptr_16); goto <bb 7>; # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), foo$ptr_19(ab)(5)> <L3>:; save_filt.2_10 = <<<filter object>>>; save_eptr.1_11 = <<<exception object>>>; D.2182_13 = foo$ptr_17(ab); operator delete (D.2182_13); <<<exception object>>> = save_eptr.1_11; <<<filter object>>> = save_filt.2_10; resx 1; <bb 7>: D.2185_14 = foo$ptr_19(ab); operator delete (D.2185_14); return 0; } the update_ssa (2048) call makes a mess out of it: int main(int, char**) (argc, D.2111) { static struct __pool pool; static struct __pool pool; int * p; struct Foo * foo$ptr; struct Foo * D.2185; struct Foo * D.2182; int save_filt.2; void * save_eptr.1; struct vector v; int (*__vtbl_ptr_type) (void) D.2148; int (*__vtbl_ptr_type) (void) * D.2147; void * D.2145; struct Foo * D.2124; <bb 2>: foo$ptr_18(ab) = 0B; if (argc_1(D) != 0) goto <bb 3>; else goto <bb 5>; <bb 3>: D.2145_2 = operator new (8); <bb 4>: D.2124_3 = (struct Foo *) D.2145_2; D.2124_3->_vptr.Foo ={v} &_ZTV3Foo[2]; <bb 5>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(2), D.2124_3(4)> foo$ptr_19(ab) = 0B; D.2147_6 = foo$ptr_19(ab)->_vptr.Foo; D.2148_7 = *D.2147_6; OBJ_TYPE_REF(D.2148_7;foo$ptr_19(ab)->0) (foo$ptr_19(ab)); goto <bb 7>; # foo$ptr_17(ab) = PHI <foo$ptr_18(ab)(3), foo$ptr_19(ab)(5)> <L3>:; save_filt.2_10 = <<<filter object>>>; save_eptr.1_11 = <<<exception object>>>; D.2182_13 = foo$ptr_17(ab); operator delete (D.2182_13); <<<exception object>>> = save_eptr.1_11; <<<filter object>>> = save_filt.2_10; resx 1; <bb 7>: D.2185_14 = foo$ptr_19(ab); operator delete (D.2185_14); return 0; }
Honza, as only foo$ptr is marked for renaming and that from update_ssa_across_eh_edges (), maybe this is a latent problem with inlining and EH info? Can you have a look?
Diego, we seem to have a general problem with the incremental SSA updater. If we rename foo$ptr in <bb 6>: # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)> p_12 = foo$ptr_16; foo$ptr_19(ab) = 0B; p_15 = foo$ptr_16; p_4 = foo$ptr_16; p_5 = foo$ptr_16; D.1781_6 = foo$ptr_16->_vptr.Foo; D.1782_7 = *D.1781_6; OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16); goto <bb 8>; it apperantly does not deal correctly with the lifetimes of foo$ptr_16 and foo$ptr_19(ab) overlapping. Note that the SSA_NAME_OCCURS_IN_ABNORMAL_PHI flags are correct, foo$ptr_16 does not live across an EH edge (but just local in BB 6). Still, for this flag to prevent creating overlapping life ranges it would have need to be set on foo$ptr_16 as well. [In the testcase the final inliner is the first one to cause renaming of foo$ptr, the early SRA pass introduces the life-range overlap (but hidden by a copy chain) and the first copyprop makes it obviously visible (that's the dump from above)]
Zdenek may also have an idea?
Subject: Re: [4.3 Regression] wrong code with -O On 30 Sep 2007 12:41:03 -0000, rguenth at gcc dot gnu dot org <gcc-bugzilla@gcc.gnu.org> wrote: > > > ------- Comment #9 from rguenth at gcc dot gnu dot org 2007-09-30 12:41 ------- > Diego, we seem to have a general problem with the incremental SSA updater. > If we rename foo$ptr in > > <bb 6>: > # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)> > p_12 = foo$ptr_16; > foo$ptr_19(ab) = 0B; > p_15 = foo$ptr_16; > p_4 = foo$ptr_16; > p_5 = foo$ptr_16; > D.1781_6 = foo$ptr_16->_vptr.Foo; > D.1782_7 = *D.1781_6; > OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16); > goto <bb 8>; Is the symbol foo$ptr being marked for renaming? If so, that's wrong. A gimple register symbol cannot be marked for renaming if there are overlapping live ranges in its SSA names. We don't have a general mechanism to prevent that. Mostly because we do not keep track when OLRs are created. The generic SSA updating mechanism has no cheap way of checking that.
Subject: Re: [4.3 Regression] wrong code with -O On Sun, 30 Sep 2007, dnovillo at google dot com wrote: > > ------- Comment #9 from rguenth at gcc dot gnu dot org 2007-09-30 12:41 ------- > > Diego, we seem to have a general problem with the incremental SSA updater. > > If we rename foo$ptr in > > > > <bb 6>: > > # foo$ptr_16 = PHI <foo$ptr_18(ab)(5), D.1758_3(4)> > > p_12 = foo$ptr_16; > > foo$ptr_19(ab) = 0B; > > p_15 = foo$ptr_16; > > p_4 = foo$ptr_16; > > p_5 = foo$ptr_16; > > D.1781_6 = foo$ptr_16->_vptr.Foo; > > D.1782_7 = *D.1781_6; > > OBJ_TYPE_REF(D.1782_7;foo$ptr_16->0) (foo$ptr_16); > > goto <bb 8>; > > Is the symbol foo$ptr being marked for renaming? If so, that's wrong. > A gimple register symbol cannot be marked for renaming if there are > overlapping live ranges in its SSA names. We don't have a general > mechanism to prevent that. Mostly because we do not keep track when > OLRs are created. The generic SSA updating mechanism has no cheap way > of checking that. Yes, it is marked for renaming by the inliner. Somehow the inliner assumes there are no OLRs: ... The function mark PHI_RESULT of such PHI nodes for renaming; it is safe the EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI must be set. This means, that there will be no overlapping live ranges for the underlying symbol. This might change in future if we allow redirecting of EH edges and we might want to change way build CFG pre-inlining to include all the possible edges then. */ static void update_ssa_across_eh_edges (basic_block bb) { edge e; edge_iterator ei; FOR_EACH_EDGE (e, ei, bb->succs) if (!e->dest->aux || ((basic_block)e->dest->aux)->index == ENTRY_BLOCK) { tree phi; gcc_assert (e->flags & EDGE_EH); for (phi = phi_nodes (e->dest); phi; phi = PHI_CHAIN (phi)) { gcc_assert (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))); mark_sym_for_renaming (SSA_NAME_VAR (PHI_RESULT (phi))); } } }
Patch at http://gcc.gnu.org/ml/gcc-patches/2007-10/msg00061.html is quite likely to fix this.
Subject: Bug 33572 Author: aoliva Date: Tue Oct 2 01:37:59 2007 New Revision: 128939 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=128939 Log: PR tree-optimization/33572 * tree-cfg.c (verify_stmts): Check for missing PHI defs. * tree-inline.c (update_ssa_across_eh_edges): Renamed to... (update_ssa_across_abnormal_edges): ... this. Set slots in the return PHI node. (copy_edges_for_bb): Handle nonlocal label edges. (make_nonlocal_label_edges): Deleted. (optimize_inline_calls): Don't call it. Modified: branches/var-tracking-assignments-branch/gcc/ChangeLog.vta branches/var-tracking-assignments-branch/gcc/tree-cfg.c branches/var-tracking-assignments-branch/gcc/tree-inline.c
Confirmed, the patch fixes it.
Subject: Bug 33572 Author: aoliva Date: Sat Oct 6 11:43:56 2007 New Revision: 129051 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129051 Log: gcc/ChangeLog: PR tree-optimization/33572 * tree-cfg.c (verify_stmts): Check for missing PHI defs. * tree-inline.c (update_ssa_across_eh_edges): Renamed to... (update_ssa_across_abnormal_edges): ... this. Set slots in the return PHI node. (copy_edges_for_bb): Handle nonlocal label edges. (make_nonlocal_label_edges): Deleted. (optimize_inline_calls): Don't call it. gcc/testsuite/ChangeLog: PR tree-optimization/33572 * g++.dg/torture/pr33572.C: New. Added: trunk/gcc/testsuite/g++.dg/torture/pr33572.C Modified: trunk/gcc/ChangeLog trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-cfg.c trunk/gcc/tree-inline.c
(In reply to comment #16) > Subject: Bug 33572 > > Author: aoliva > Date: Sat Oct 6 11:43:56 2007 > New Revision: 129051 > > URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129051 > Log: > gcc/ChangeLog: > PR tree-optimization/33572 > * tree-cfg.c (verify_stmts): Check for missing PHI defs. > * tree-inline.c (update_ssa_across_eh_edges): Renamed to... > (update_ssa_across_abnormal_edges): ... this. Set slots in the > return PHI node. > (copy_edges_for_bb): Handle nonlocal label edges. > (make_nonlocal_label_edges): Deleted. > (optimize_inline_calls): Don't call it. > gcc/testsuite/ChangeLog: > PR tree-optimization/33572 > * g++.dg/torture/pr33572.C: New. > > Added: > trunk/gcc/testsuite/g++.dg/torture/pr33572.C > Modified: > trunk/gcc/ChangeLog > trunk/gcc/testsuite/ChangeLog > trunk/gcc/tree-cfg.c > trunk/gcc/tree-inline.c > g++.dg/torture/pr33572.C failed on Linux/ia32: Executing on host: /export/build/gnu/gcc/build-i686-linux/gcc/testsuite/g++/../../g++ -B/export/build/gnu/gcc/build-i686-linux/gcc/testsuite/g++/../../ /net/gnu-13/export/gnu/src/gcc/gcc/gcc/testsuite/g++.dg/torture/pr33572.C -nostdinc++ -I/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/libstdc++-v3/include/i686-pc-linux-gnu -I/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/libstdc++-v3/include -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/libsupc++ -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/include/backward -I/net/gnu-13/export/gnu/src/gcc/gcc/libstdc++-v3/testsuite/util -fmessage-length=0 -O0 -fno-show-column -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libstdc++-v3/src/.libs -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libstdc++-v3/src/.libs -L/export/build/gnu/gcc/build-i686-linux/i686-pc-linux-gnu/./libiberty -lm -o ./pr33572.exe (timeout = 300) /tmp/ccSsvTAh.o: In function `vector::deallocate(int*)':^M pr33572.C:(.text._ZN6vector10deallocateEPi[_ZN6vector10deallocateEPi]+0x24): undefined reference to `__gnu_cxx::__pool<true>::_M_reclaim_block(char*, unsigned long)'^M collect2: ld returned 1 exit status^M
I see the same failure as HJL on hppa-unknown-linux-gnu.
Subject: Bug 33572 Author: aoliva Date: Mon Oct 8 23:57:20 2007 New Revision: 129144 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129144 Log: PR tree-optimization/33572 * g++.dg/torture/pr33572.C: Replace with complete test. Modified: trunk/gcc/testsuite/ChangeLog trunk/gcc/testsuite/g++.dg/torture/pr33572.C
Subject: Bug 33572 Author: aoliva Date: Tue Oct 9 04:46:49 2007 New Revision: 129151 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129151 Log: PR tree-optimization/33572 * tree-inline.c (update_ssa_across_abnormal_edges): Tolerate the absence of a corresponding edge from the exit block. Modified: trunk/gcc/ChangeLog trunk/gcc/tree-inline.c
Fixed.
Subject: Bug 33572 Author: aoliva Date: Mon Oct 15 17:07:20 2007 New Revision: 129356 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=129356 Log: gcc/ChangeLog: PR tree-optimization/33735 PR tree-optimization/33572 * tree-inline.c (update_ssa_across_abnormal_edges): Revert 2007-10-09's change. * except.c (duplicate_eh_regions): Don't look for prev_try beyond ERT_ALLOWED_EXCEPTIONS with an empty list. gcc/testsuite/ChangeLog: PR tree-optimization/33735 * g++.dg/torture/pr33735.C: New. Added: trunk/gcc/testsuite/g++.dg/torture/pr33735.C Modified: trunk/gcc/ChangeLog trunk/gcc/except.c trunk/gcc/testsuite/ChangeLog trunk/gcc/tree-inline.c