This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Non-call-exceptions, unwinding and g++ optimization levels


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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]