I may have found a situation where GCC's optimizations causes a constructor to be skipped that leads to a crash. This problem first manifested itself in a program involving well over 100000 lines of code (not including the extra lines from #include'd files). The initial problem is in code generated by Babel, http://www.llnl.gov/CASC/compnents/, in the runC2Cxx program part of the objarg regression test. After many hours of work, I've reproduced the bug with a program involving only 324 lines.
% wc *.c *.h *.hxx *.cxx 45 108 861 main.c 55 136 1174 RefCount.c 35 59 503 RefCount.h 78 170 1426 Wrapper.hxx 111 239 2052 Wrapper.cxx 324 712 6016 total I compile these files with the following script: #!/bin/sh \rm -f *.o test_aliasing test_noaliasing gcc-4.2 -g -O2 -c RefCount.c main.c Wrapper.cxx g++-4.2 -g -O2 -o test_aliasing RefCount.o main.o Wrapper.o gcc-4.2 -g -O2 -fno-strict-aliasing -c RefCount.c main.c Wrapper.cxx g++-4.2 -g -O2 -fno-strict-aliasing -o test_noaliasing RefCount.o main.o Wrapper.o ./test_noaliasing runs without crashing, and ./test_aliasing crashes in this operator= method: TestClass & TestClass::operator =(const TestClass &rhs) { if (d_self != rhs.d_self) { if (d_self) { /* segfault at next line because d_self wasn't initialized to 0 */ deleteRef(reinterpret_cast< struct RefCount_t * >(d_self)); } d_self = rhs.d_self; if (d_self) { addRef(reinterpret_cast< struct RefCount_t * >(d_self)); } } return *this; } when called from this extern "C" function: struct Test * getItem(struct C_Container *cont, int ind) { struct Test *result = 0; TestClass _local_result; try { _local_result = cont->d_cont->at(ind); /* crash here */ } catch(...) { return result; } result = _local_result.getIOR(); if (result) { addRef(reinterpret_cast<struct RefCount_t *>(result)); } return result; } In getItem, it appears to have skipped executing empty constructor for _local_result that initializes d_self to 0. Here is the declaration for TestClass and its super classes. class BaseClass { protected: void *d_self; public: BaseClass() : d_self(0) {} BaseClass(void *ior) : d_self(ior) {} ~BaseClass() { if (d_self) { struct RefCount_t *ref = reinterpret_cast<struct RefCount_t *>(d_self); deleteRef(ref); d_self = 0; } } }; class NextClass : public virtual BaseClass { public: typedef struct Next ior_t; NextClass() {} NextClass(ior_t *ior); }; class TestClass : public virtual NextClass { public: typedef struct Test ior_t; TestClass() {} TestClass(ior_t *ior); virtual ~TestClass() { } TestClass(const TestClass &src); TestClass& operator= (const TestClass &rhs); ior_t *getIOR() const { return reinterpret_cast < ior_t *>(d_self); } long getNum() const { return reinterpret_cast< Test *>(d_self)->num; } }; My understanding is the _local_result should be initialized by running with the TestClass::TestClass() constructor which fires after the NextClass::NextClass() constructor which fires after the BaseClass::BaseClass() constructor where d_self is initialized to 0. If I add a printf("Hello\n"); call inside the BaseClass() constructor, it runs and the program doesn't segfault. The output from running valgrind on the executable supports the idea that d_self is not being initialized. % valgrind ./test_aliasing ==30651== Memcheck, a memory error detector. ==30651== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al. ==30651== Using LibVEX rev 1732, a library for dynamic binary translation. ==30651== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP. ==30651== Using valgrind-3.2.3-Debian, a dynamic binary instrumentation framework. ==30651== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al. ==30651== For more details, rerun with: -v ==30651== ==30651== Conditional jump or move depends on uninitialised value(s) ==30651== at 0x80489E5: TestClass::operator=(TestClass const&) (Wrapper.cxx:30) ==30651== by 0x8048BE2: getItem (Wrapper.cxx:101) ==30651== by 0x804887B: main (main.c:35) ==30651== ==30651== Conditional jump or move depends on uninitialised value(s) ==30651== at 0x80489E9: TestClass::operator=(TestClass const&) (Wrapper.cxx:31) ==30651== by 0x8048BE2: getItem (Wrapper.cxx:101) ==30651== by 0x804887B: main (main.c:35) ==30651== ==30651== Use of uninitialised value of size 4 ==30651== at 0x8048716: deleteRef (RefCount.c:52) ==30651== by 0x80489F2: TestClass::operator=(TestClass const&) (Wrapper.cxx:33) ==30651== by 0x8048BE2: getItem (Wrapper.cxx:101) ==30651== by 0x804887B: main (main.c:35) ==30651== ==30651== Process terminating with default action of signal 11 (SIGSEGV) ==30651== Bad permissions for mapped region at address 0x8048EB4 ==30651== at 0x804871D: deleteRef (RefCount.c:52) ==30651== by 0x80489F2: TestClass::operator=(TestClass const&) (Wrapper.cxx:33) ==30651== by 0x8048BE2: getItem (Wrapper.cxx:101) ==30651== by 0x804887B: main (main.c:35) ==30651== ==30651== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 19 from 1) ==30651== malloc/free: in use at exit: 1,008 bytes in 12 blocks. ==30651== malloc/free: 12 allocs, 0 frees, 1,008 bytes allocated. ==30651== For counts of detected errors, rerun with: -v ==30651== searching for pointers to 12 not-freed blocks. ==30651== checked 100,788 bytes. ==30651== ==30651== LEAK SUMMARY: ==30651== definitely lost: 0 bytes in 0 blocks. ==30651== possibly lost: 0 bytes in 0 blocks. ==30651== still reachable: 1,008 bytes in 12 blocks. ==30651== suppressed: 0 bytes in 0 blocks. ==30651== Rerun with --leak-check=full to see details of leaked memory. Segmentation fault The program doesn't crash when compiled with Intel's 9.0.21 C++ compiler. It doesn't crash when compiled with pre-4.2 GCC versions either. Based on this evidence, it seems possible that this illustrates a case of over zealous optimization. Release: gcc-4.2 (GCC) 4.2.1 20070525 (prerelease) (Debian 4.2-20070525-1) System: Linux driftcreek 2.6.18-4-686 #1 SMP Wed May 9 23:03:12 UTC 2007 i686 GNU/Linux Architecture: i686 configured with: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.2 --program-suffix=-4.2 --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-targets=all --disable-werror --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu -- Summary: -fstrict-aliasing optimizations cause constructor not to run in causing segfault Product: gcc Version: 4.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: epperly2 at llnl dot gov GCC build triplet: i486-pc-linux-gnu GCC host triplet: i486-pc-linux-gnu GCC target triplet: i486-pc-linux-gnu http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32182