In our application we want to translate synchronous signals (such as SIGSEGV) to C++ exceptions. The method is to use throw directly from either: 1 - From the signal handler itself. 2 - From a function called by the signal handler. I'm having trouble getting this to work reliably. Test program attached below. Building and running: $ g++ sigthrow.cpp -fnon-call-exceptions -fexceptions $ a.out terminate called after throwing an instance of 'char const*' Aborted (core dumped) $ Removing option -fnon-call-exceptions gives: $ g++ sigthrow.cpp -fexceptions $ a.out ~StructWithDtor: Count 0 Caught exception So it works, except the frame that generated the exception is not cleaned up (it should call a destructor for another instance of StructWithDtor). The pattern seems to be: 1 - If the function generating the signal has objects to unwind, this is always missed. 2 - Also, when compiled with -fnon-call-exceptions the program often (not always) aborts. 3 - If the function generating the signal does not have objects to unwind it goes well (with or without -fnon-call-exceptions) Are there some other compiler option to make this work? Something to be done in the signal handler? So far I haven't found any working examples of this functionality on the web. But others have found similar difficulties. What is the status of this? It's an important feature when using plugins, script interpreters and linking with code from other languages. Regards // ATS. ----------------- source ------------------------------- #include <stdio.h> #include <csignal> #include <unistd.h> #include <sys/syscall.h> typedef void(*stSignalHandlerFn)(int); struct old_i386_kernel_sigaction { stSignalHandlerFn k_sa_handler; unsigned long k_sa_mask; unsigned long k_sa_flags; void (*sa_restorer) (void); }; void stSigSegvHandler( int dummy ){ void **_p = (void **)&dummy; struct sigcontext_struct *_regs = (struct sigcontext_struct *)++_p; throw "SIGSEGV signaled"; } int g_cnt; struct StructWithDtor { StructWithDtor() : m_cnt(g_cnt++) { } ~StructWithDtor(){ printf("~StructWithDtor: Count %d\n", m_cnt); } int m_cnt; }; int FuncNested1( int *pi ){ StructWithDtor swd; return *pi; } int FuncTop( int *pi ){ StructWithDtor swd; return FuncNested1( pi ); } int main( int argc, const char* argv[] ) { // Install a SIGSEGV handler using syscall struct old_i386_kernel_sigaction kact; kact.k_sa_handler = stSigSegvHandler; kact.k_sa_mask = 0; kact.k_sa_flags = 0; syscall( SYS_sigaction, SIGSEGV, &kact, NULL ); // Trigger SIGSEGV try { FuncTop( NULL ); }catch( ... ){ puts( "Caught exception\n" ); } }
I found something out. If I add a further function call to FuncNested1: int FuncNested2( ){ StructWithDtor swd; return 0; } int FuncNested1( int *pi ){ StructWithDtor swd; FuncNested2( ); // This trigger unwind table generation return *pi; } then it works. It seems that FuncNested1 in the first form: int FuncNested1( int *pi ){ StructWithDtor swd; return *pi; } never generates any unwinding information (since it doesn't call other functions) and when SIGSEGV happens inside it, it cannot find any unwind tables and C++ run-time bails out. I can understand the logic behind this, but it certainly made my first test case fail miserably. In a realworld app, the optimization is probably OK, since a function generating the signal is likely to contain other function calls (not bullet proof). It is possible to interpret -asynchronous-unwind-tables to support this but that option changes nothing for my test case. An option -always-generate-unwind-tables would be useful in this case (but probably results in a larger executable). Regards // ATS.
Created attachment 14728 [details] proposed fix I'm seeing similar behavior on x86-64 with both g++-4.1.3 (ubuntu-7.10 dist) and g++-4.2.2 build from sources. I spent some time in the debugger and I've identified the problem and a fix. It looks like the problem first appeared in r115654. The change to eh_personality.cc guards a call to _Unwind_GetIPInfo with the preprocessor macro HAVE_GETIPINFO. Unfortunately, that macro HAVE_GETIPINFO is never defined in c++config.h; _GLIBCXX_HAVE_GETIPINFO is. The attached patch (against gcc-4.2.2) fixes this issue and the resulting libstdc++.so.6.0.9 produces the desired behavior. Thanks, -Ted
Added Steve Ellcey to the CC as he's the author of r115654. Hope that's not rude. Thanks, -Ted
(In reply to comment #2) > Created an attachment (id=14728) [edit] > proposed fix > > I'm seeing similar behavior on x86-64 with both g++-4.1.3 (ubuntu-7.10 dist) > and g++-4.2.2 build from sources. I spent some time in the debugger and I've > identified the problem and a fix. > > ... > > The attached patch (against gcc-4.2.2) fixes this issue and the resulting > libstdc++.so.6.0.9 produces the desired behavior. > Good to see a solution. When/where is it reasonable to expect the patch in a release? Would it go into 4.2 or 4.3 or would it be backported to 4.1 series? Regards // ATS
Created attachment 14732 [details] minimal test case This attachment contains a minimal C++ program that exhibits the behavior. The program should exit with a return code of 0, but without the patch above it produces the following output: terminate called after throwing an instance of 'int' -Ted
Benjamin, the patch in #c4 looks good to me and this is a very severe bug, could you please review the patch and apply if you agree? Wonder what kind of testing was done before r115654 commit :(.
(In reply to comment #2) > Created an attachment (id=14728) [edit] > proposed fix > > I'm seeing similar behavior on x86-64 with both g++-4.1.3 (ubuntu-7.10 dist) > and g++-4.2.2 build from sources. I spent some time in the debugger and I've > identified the problem and a fix. > I've applied this path to GCC 4.3.0 (as of 2008-01-04). Unfortunately the problem is still there for me. Both in the original test case and in the non-call-except-cpp test case. Regards // ATS > > Thanks, > -Ted >
Subject: Bug 34152 Author: jakub Date: Sun Jan 6 20:25:57 2008 New Revision: 131361 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131361 Log: PR c++/34152 * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Check _GLIBCXX_HAVE_GETIPINFO instead of HAVE_GETIPINFO. Modified: trunk/libstdc++-v3/ChangeLog trunk/libstdc++-v3/libsupc++/eh_personality.cc
(In reply to comment #8) > Subject: Bug 34152 > > Author: jakub > Date: Sun Jan 6 20:25:57 2008 > New Revision: 131361 > > URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131361 > Log: > PR c++/34152 > * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Check > _GLIBCXX_HAVE_GETIPINFO instead of HAVE_GETIPINFO. I've checked this. From line 446 of libsupc++/eh_personality.cc: // Parse the LSDA header. p = parse_lsda_header (context, language_specific_data, &info); info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); #ifdef _GLIBCXX_HAVE_GETIPINFO ip = _Unwind_GetIPInfo (context, &ip_before_insn); #else ip = _Unwind_GetIP (context); #endif I've rebuild with the patch in a clean directory. g++ --version gives: $ g++43 --version g++43 (GCC) 4.3.0 20080104 (experimental) Regards // ATS > > Modified: > trunk/libstdc++-v3/ChangeLog > trunk/libstdc++-v3/libsupc++/eh_personality.cc >
(In reply to comment #9) > (In reply to comment #8) > > Subject: Bug 34152 > > > > * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Check > > _GLIBCXX_HAVE_GETIPINFO instead of HAVE_GETIPINFO. > > I've checked this. From line 446 of libsupc++/eh_personality.cc: The trouble was that the GCC 4.3 was linking executables to the old version of libstdc++ (4.1). Setting LD_LIBRARY_PATH did the trick. Both test cases work now. Regards // ATS
Subject: Bug 34152 Author: jakub Date: Mon Jan 7 16:05:27 2008 New Revision: 131376 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=131376 Log: PR c++/34152 * libsupc++/eh_personality.cc (PERSONALITY_FUNCTION): Check _GLIBCXX_HAVE_GETIPINFO instead of HAVE_GETIPINFO. Modified: branches/gcc-4_2-branch/libstdc++-v3/ChangeLog branches/gcc-4_2-branch/libstdc++-v3/libsupc++/eh_personality.cc
re: comment #7, could you double-check with ldd that your application is picking up the right libstdc++.so? You may have to fiddle with your LD_LIBRARY_PATH to make it do so. -Ted
re: comment #12 -- sorry, just read comment #10. Ignore me.
*** Bug 35555 has been marked as a duplicate of this bug. ***
I had missed to use the flag -fnon-call-exceptions. With that enabled it works as it should. Regards // ATS
So, fixed long time ago.