//fork/throw SEGFAULT issue //a SEGFAULT occurs under these circumstances only: // 1. compile with g++-4 (4.3.4 20090804) on cygwin 1.7.5-1 // - g++-3 does not have this issue, and cyg 1.7.4-1 were intermittent(?) // 2. fork at least once // 3. enter try block in parent (before fork) or child // 4. throw a derived exception class in the child // 5. where the derived class contains a std::string member // 6. catch std::exception //To see the SEGFAULT, you will need error_start=dumper.exe //or something similar in the CYGWIN environmental variable //set to -1 to disable forking //must fork to crash #define FORK_LIMIT 1 //enter the try block in the parent but throw in the child //both versions crash #define TRY_BEFORE_FORK 1 //0 means throw in parent //must throw in child to crash #define THROW_IN_CHILD 1 //these crash //#define EXCEPTION_ stringexcept(string("exception")) #define EXCEPTION_ stringexcept() //these don't crash //#define EXCEPTION_ exception() //#define EXCEPTION_ string("exception") //#define EXCEPTION_ "exception" //this doesn't crash //#define CATCH_TYPE stringexcept //these crash #define CATCH_TYPE exception //#define CATCH_TYPE exception& //this doesn't crash //#define CATCH_TYPE string //#define CATCH_TYPE const char * //define destructor inline //both crash #define INLINE_DESTRUCTOR 1 //derived exception class has a std::string member #define USE_STRING 1 //printing has no impact on the SEGFAULT //control debugging and exception output #define PRINT_EXCEPTION 0 #define PRINT_DEBUG 0 #include #include #include #include #include using namespace std; class stringexcept : public exception { public: stringexcept() : exception() #if USE_STRING ,_what() #endif { } stringexcept(string s) : exception() #if USE_STRING ,_what(s) #endif { } virtual ~stringexcept() throw() #if INLINE_DESTRUCTOR {} #else ; #endif #if USE_STRING //overriding what() makes no difference //virtual const char* what() const throw() { // return _what.c_str(); //} protected: string _what; #endif }; #if !INLINE_DESTRUCTOR stringexcept::~stringexcept() throw() {} #endif int main(int, char**) { #if TRY_BEFORE_FORK try { #endif pid_t orig_pid = getpid(); int fork_count = 0; while (fork_count < FORK_LIMIT) { pid_t pid = fork(); fork_count++; if (pid == 0) { #if PRINT_DEBUG cerr << "fork() succeeded - child: " << getpid() << endl; #endif } else if (pid > 0) { #if PRINT_DEBUG cerr << "fork() succeeded - parent: " << getpid() << " forked child: " << pid << endl; cerr << "parent breaking loop" << endl; #endif break; } else { #if PRINT_DEBUG cerr << "fork() failed" << endl; cerr << "parent exiting" << endl; #endif exit(1); } //if parent/child } //while fork limit not exceeded #if !TRY_BEFORE_FORK try { #endif if (THROW_IN_CHILD == (getpid() != orig_pid)) { #if PRINT_DEBUG cerr << "throwing exception" << endl; #endif throw EXCEPTION_; } } catch(CATCH_TYPE e) { #if PRINT_EXCEPTION //sleep causes the exception output to come last //after a large series of fork()s //sleep(5); //overriding what() makes no difference cerr << "Exception: " //<< e.what() << " in pid: " << getpid() << endl; cerr << endl; #endif } return 0; }