Bug 34152 - Erratic behaviour: Exception translation (throw from signal handlers)
Summary: Erratic behaviour: Exception translation (throw from signal handlers)
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.3
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
: 35555 (view as bug list)
Depends on:
Blocks:
 
Reported: 2007-11-19 14:38 UTC by Arne Steinarson
Modified: 2011-11-07 16:27 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
proposed fix (361 bytes, patch)
2007-12-11 10:38 UTC, Ted Phelps
Details | Diff
minimal test case (323 bytes, text/plain)
2007-12-11 22:30 UTC, Ted Phelps
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Arne Steinarson 2007-11-19 14:38:46 UTC
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" );
    }

}
Comment 1 Arne Steinarson 2007-11-19 16:21:28 UTC
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.
Comment 2 Ted Phelps 2007-12-11 10:38:39 UTC
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
Comment 3 Ted Phelps 2007-12-11 10:43:06 UTC
Added Steve Ellcey to the CC as he's the author of r115654.  Hope that's not rude.

Thanks,
-Ted
Comment 4 Arne Steinarson 2007-12-11 17:55:34 UTC
(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

Comment 5 Ted Phelps 2007-12-11 22:30:32 UTC
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
Comment 6 Jakub Jelinek 2007-12-11 22:49:26 UTC
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 :(.
Comment 7 Arne Steinarson 2008-01-06 17:02:55 UTC
(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
> 

Comment 8 Jakub Jelinek 2008-01-06 20:26:35 UTC
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

Comment 9 Arne Steinarson 2008-01-06 23:18:24 UTC
(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
> 

Comment 10 Arne Steinarson 2008-01-07 13:24:09 UTC
(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
Comment 11 Jakub Jelinek 2008-01-07 16:06:06 UTC
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

Comment 12 Ted Phelps 2008-01-09 05:53:46 UTC
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
Comment 13 Ted Phelps 2008-01-09 05:54:50 UTC
re: comment #12 -- sorry, just read comment #10.  Ignore me.
Comment 14 Andrew Pinski 2008-03-12 16:14:01 UTC
*** Bug 35555 has been marked as a duplicate of this bug. ***
Comment 15 Arne Steinarson 2008-03-12 16:41:45 UTC
I had missed to use the flag -fnon-call-exceptions.  

With that enabled it works as it should. 

Regards
// ATS
Comment 16 Paolo Carlini 2011-11-07 16:27:49 UTC
So, fixed long time ago.