Good day, I'm working with exceptions thrown by a signal handler using -fnon-call-exceptions flag with g++ for x86_64.
The problem I am facing is that the behavior of this mechanism is not consistent if we change some optimization options, that is, the result of a given program can be different. In order to make a comparison, I ran this test several times, each with different optimizations enabled. Compilation either with -O0 or without any flags (just -fnon-call-exceptions): Exception is caught at the "copy" function (the one which calls std::copy). This is the expected behavior. Compilation using -O1 -O2 or -O3 flag directly: Exception is not being caught. If both -fno-inline and -fno-ipa-pure-const are used, then the program behaves as if -O0 is used. Thus, I tried to add __attribute__((noinline)) to both "foo" and "copy" functions. It seems that they were ignored because the problem doesn't dissapear when -fno-inline is not used. In my opinion, it seems that catch blocks are being optimized out or that, because of the inlining, the generated code is not able to find any catch blocks inside its scope. I could reproduce this with g++ versions 4.7.3, 4.8.1 and the latest in the public, read-only, git. The file used to test this is attached to the message. Compile command used is: g++ -fnon-call-exceptions [-fno-inline -fno-ipa-pure-const] -O{0,1,2,3} Regards, Jorge
#include <stdexcept> #include <exception> #include <iostream> #include <algorithm> #include <signal.h> #include <sys/mman.h> #include <assert.h> /* * This program tries to check how exceptions unwind * when they are thrown inside a signal handler * (using -fnon-call-exceptions code generation flag) */ typedef void* ptr_t; void copy( ptr_t from, ptr_t to, size_t size ) { try { char *beg = (char*)from; char *end = (char*)from + size; char *dst = (char*)to; std::copy(beg, end, dst); } catch (std::exception &e) { std::cout << "Caught in copy function" << std::endl; } } void taskErrorHandler ( int sig, siginfo_t* si, void *context ) { throw std::runtime_error("I've found an error!"); } void foo(int *from, int *to, size_t length) { try { copy((ptr_t)from, (ptr_t)to, length); } catch (std::exception &e) { std::cout << "Caught in foo function" << std::endl; } } int main() { // Installs a signal handler for SIGSEGV signals struct sigaction recovery_action; recovery_action.sa_sigaction = &taskErrorHandler; sigemptyset(&recovery_action.sa_mask); recovery_action.sa_flags = SA_SIGINFO; sigaction(SIGSEGV, &recovery_action, NULL); size_t memsize = 4096; int *from, *to; // Allocates two portions of memory aligned to a memory page. assert( posix_memalign( (ptr_t*) &from, 4096, memsize) == 0 ); assert( posix_memalign( (ptr_t*) &to, 4096, memsize) == 0 ); mprotect( from, memsize, PROT_NONE);// Block access to the source allocation try { foo(from, to, memsize); } catch (std::exception &e) { std::cout << "Caught in main function" << std::endl; } return 0; }