SYMPTOM: If evaluating the expression in a return statement in a try-block throws an exception, the program crashes with a segfault or uses random data at the point mentioned in the code snippet below. Compiled with g++ -W -Wall -O. CODE SNIPPET: (full example code below) template<> std::string real_cast ( const std::string & value ) { try { return mk( value ); // bug triggered by mk throwing a std::string } catch ( std::string & s ) { throw s + value; // segfaults in std::string::operator+ } } WORKAROUND: The problem goes away by either of (1) not compiling with -O (2) using an explicit temporary for the return value: std::string nrv; try { nrv = ... } catch ... { } return nrv; ADDITIONAL ANALYSIS: While debugging with gdb, it seemed that the stack got corrupted, i.e. while the value of "note" was ok before the return statement, it was mangled when execution reached the catch block; similar for the "this" pointer in case of "foo" being a member function. The full code below shows that the corruption cannot be a side-effect of "somefunc". OS VERSION: uname -a SunOS xxxxxx 5.8 Generic_108528-20 sun4u sparc SUNW,Sun-Fire-880 Solaris COMPILER VERSIONS: Reading specs from /opt/local.source/lib/gcc-lib/sparc-sun-solaris2.8/3.3.2/specs Configured with: ./configure --prefix=/opt/local.source --enable-shared --enable-threads --with-cpu=v9 --enable-languages=c,c++ --disable-libgcj --disable-multilib --with-gnu-as --with-as=/opt/global/gcc-3.3-32-solaris8-108528-20/bin/as --with-gnu-ld --with-ld=/opt/global/gcc-3.3-32-solaris8-108528-20/bin/ld Thread model: posix gcc version 3.3.2 20030908 (prerelease) Reading specs from /opt/global/gcc-3.3-32-solaris8-108528-20/lib/gcc-lib/sparc-sun-solaris2.8/3.3/specs Configured with: ../gcc-3.3/configure --prefix=/opt/global/gcc-3.3-32-solaris8-108528-20 --enable-shared --enable-threads --with-cpu=v9 --with-gnu-as --with-as=/opt/global/gcc-3.3-32-solaris8-108528-20/bin/as --with-gnu-ld --with-ld=/opt/global/gcc-3.3-32-solaris8-108528-20/bin/ld --disable-multilib Thread model: posix gcc version 3.3 SOURCE CODE: #include <string> #include <iostream> // Program to trigger a bug in GCC 3.3* / Sparc / Solaris 2.8 // compile with "g++ -O -W -Wall" to trigger bug // compile without optimisation produces non-crashing version template< class T > T real_cast( const std::string & ); template< class T > T cast_helper( const std::string & value, const std::string & debug ) { try { return real_cast< T >( value ); } catch ( std::string & e ) { throw e + debug; } } struct Value { Value( const std::string & value ) : m_value( value ) {} template< class T > T get( const std::string & debug ) const { if ( m_value.empty() ) throw std::string( "empty" ); else return cast_helper< T >( m_value, debug ); } const std::string m_value; }; std::string mk( const std::string & value ) { if ( value.length() < 4 ) return value + value; else throw value + value; } template<> std::string real_cast ( const std::string & value ) { try { return mk( value ); } catch ( std::string & s ) { throw s + value; // segfaults in std::string::operator+ } } int main( int, char ** ) { try { Value error( "error" ); const std::string error_s = error.get< std::string >( "error string" ); std::cerr << error_s << '\n'; } catch ( std::string & e ) { std::cerr << "exception [ " << e << " ]\n"; } return 0; }
I can't reproduce this on a linux box, so we need someone with a sparc. Christian? W.
I can confirm the crash on sparc with recent 3.4. Apparently the value of debug in function cast_helper is not preserved accross the try block and the catch block tries to throw chunk. Here's a reduced self contained testcase that crashes on sparc if compiled with -O. Note that adding debug output sometimes makes the bug go away. // #include <iostream> struct S{ char * c; char data[100]; S () : c (data) {}; S (const S & s) { c = data; data[0] = s.c[0]; } }; S real_cast () { throw 3; } S cast_helper( S & debug ) { // std::cerr << &debug << std::endl; /* AAA */ try { return real_cast(); } catch ( int e) { // std::cerr << "HO " << &e << " "<< &debug << std::endl; throw debug; } } int main( ) { S tmp; try { cast_helper ( tmp ); } catch ( S & e ) { } return 0; }
I can confirm the crash on GCC 3.2.2, 3.2.3, 3.3 and 3.3.2pre with Christian's testcase, but GCC 2.95.3 doesn't crash so we have a regression.
Fixing.
Subject: Bug 12301 CVSROOT: /cvs/gcc Module name: gcc Changes by: ebotcazou@gcc.gnu.org 2003-09-21 08:17:48 Modified files: gcc : ChangeLog reorg.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/eh: delayslot1.C Log message: PR target/12301 * reorg.c (stop_search_p): Return 1 for insns that can throw internally. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.1109&r2=2.1110 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/reorg.c.diff?cvsroot=gcc&r1=1.87&r2=1.88 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.3074&r2=1.3075 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/eh/delayslot1.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
Subject: Bug 12301 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_3-branch Changes by: ebotcazou@gcc.gnu.org 2003-09-21 08:22:34 Modified files: gcc : ChangeLog reorg.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/eh: delayslot1.C Log message: PR target/12301 * reorg.c (stop_search_p): Return 1 for insns that can throw internally. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.16114.2.748&r2=1.16114.2.749 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/reorg.c.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.82&r2=1.82.4.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=1.2261.2.284&r2=1.2261.2.285 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/eh/delayslot1.C.diff?cvsroot=gcc&only_with_tag=gcc-3_3-branch&r1=NONE&r2=1.1.2.1
See http://gcc.gnu.org/ml/gcc-patches/2003-09/msg01313.html