Reputation: 1553
The following code :
main.cpp :
# include <iostream>
# include <csetjmp>
# include <stdexcept>
using namespace std ;
void do_work(jmp_buf context)
{
try
{
throw runtime_error("Ouch !") ;
}
catch(exception & e)
{
}
longjmp(context, -1) ; //BP1
}
int main(int, char *[])
{
jmp_buf context ;
try
{
if( setjmp(context) != 0 )
{
throw runtime_error("Oops !") ; //BP2
}
do_work(context) ;
}
catch(exception & e)
{
cout << "Caught an exception saying : " << e.what() << endl ;
}
}
I tried debugging it but the program behaves strangely. Sometimes I could get past the first breakpoint (BP1), then crash at BP2, and sometimes control never reachs BP1, like if the program is stuck in an infinite loop. I cannot say more with my debugging skills.
This code is the minimal I could get that exhibits the strange behavior with MinGW 4.5. I also noticed that :
do_work
function call by its content, the program runs fine.try{ ... } catch(...){ }
block inside do_work
, the program runs fine.I'm aware of the setjmp/longjmp
issues in C++ code, but I'm forced to use it to interface with some legacy C code.
My question :
Thanks for any advice.
Please retag if necessary.
Upvotes: 6
Views: 625
Reputation: 38932
The longjmp(3) man page on Unix says:
The longjmp() routines may not be called after the routine which called the setjmp() routines returns
I think it explains explains your concern that "sometimes control never reachs BP1". I don't think "runs fine" is reliable judgement. I'd rather expect it randomly runs fine and generally is messing up with stack.
There are a few clear recommendations that should be taken into account while working mixing longjmp/setjmp with C++ exceptions in order to avoid crashes and undefined behaviour:
The question mentions dealing with legacy C code in programs written in C++. There has been an interesting discussion on sjlj issues in jpeg library during review of one of Boost libraries. The discussion was long but here is essence with recommended options.
Upvotes: 3
Reputation: 13806
C++ only makes one additional restriction on the use of longjmp()
:
If any automatic objects would be destroyed by a thrown exception transferring control to another (destination) point in the program, then a call to longjmp(jbuf, val) at the throw point that transfers control to the same (destination) point has undefined behavior. (18.7)
You seem to be aware of this, and your program doesn't do it. I vote compiler defect.
Upvotes: 1
Reputation: 26171
longjmp
and setjmp
are c functions, invoking them with C++ exception handling semantics and object destruction semantics is undefined behavior, which means its up to the implementation whether it works or not (your testing shows this, the SEH stack unwind semantics break things, depending on the type used, iirc your working ones are using dwarf2)
Upvotes: 0