What is the best way to measure exception handling overhead/performance in C++?
Please give standalone code samples.
I'm targeting Microsoft Visual C++ 2008 and gcc.
I need to get results from the following cases:
Overhead when there are no try/catch blocks
Overhead when there are try/catch blocks but exceptions are not thrown
Overhead when exceptions are thrown
Section 5.4 of the draft Technical Report on C++ Performance is entirely devoted to the overhead of exceptions.
As a suggestion: don't bother too much with the overhead when exceptions are thrown. Exception handling implementations usually make not throwing fast and catching slow. That's ok since those cases are, well, exceptional.
Carl
Here's the measuring code I came up with. Do you see any problems with it?
Works on Linux and Windows so far, compile with:
g++ exception_handling.cpp -o exception_handling [ -O2 ]
or for example Visual C++ Express.
To get the base case ("exception support removed from the language altogether"), use:
g++ exception_handling.cpp -o exception_handling [ -O2 ] -fno-exceptions -DNO_EXCEPTIONS
or similar settings in MSVC.
Some preliminary results here. They are probably all hokey because of varying machine load, but they do give some idea about the relative exception handling overhead. (Executive summary: none or little when no exceptions are thrown, huge when they actually are thrown.)
#include <stdio.h>
// Timer code
#if defined(__linux__)
#include <sys/time.h>
#include <time.h>
double time()
{
timeval tv;
gettimeofday(&tv, 0);
return 1.0 * tv.tv_sec + 0.000001 * tv.tv_usec;
}
#elif defined(_WIN32)
#include <windows.h>
double get_performance_frequency()
{
unsigned _int64 frequency;
QueryPerformanceFrequency((LARGE_INTEGER*) &frequency); // just assume it works
return double(frequency);
}
double performance_frequency = get_performance_frequency();
double time()
{
unsigned _int64 counter;
QueryPerformanceCounter((LARGE_INTEGER*) &counter);
return double(counter) / performance_frequency;
}
#else
# error time() not implemented for your platform
#endif
// How many times to repeat the whole test
const int repeats = 10;
// How many times to iterate one case
const int times = 1000000;
// Trick optimizer to not remove code
int result = 0;
// Case 1. No exception thrown nor handled.
void do_something()
{
++result;
}
void case1()
{
do_something();
}
// Case 2. No exception thrown, but handler installed
#ifndef NO_EXCEPTIONS
void do_something_else()
{
--result;
}
void case2()
{
try
{
do_something();
}
catch (int exception)
{
do_something_else();
}
}
// Case 3. Exception thrown and caught
void do_something_and_throw()
{
throw ++result;
}
void case3()
{
try
{
do_something_and_throw();
}
catch (int exception)
{
result = exception;
}
}
#endif // !NO_EXCEPTIONS
void (*tests[])() =
{
case1,
#ifndef NO_EXCEPTIONS
case2,
case3
#endif // !NO_EXCEPTIONS
};
int main()
{
#ifdef NO_EXCEPTIONS
printf("case0\n");
#else
printf("case1\tcase2\tcase3\n");
#endif
for (int repeat = 0; repeat < repeats; ++repeat)
{
for (int test = 0; test < sizeof(tests)/sizeof(tests[0]); ++test)
{
double start = time();
for (int i = 0; i < times; ++i)
tests[test]();
double end = time();
printf("%f\t", (end - start) * 1000000.0 / times);
}
printf("\n");
}
return result; // optimizer is happy - we produce a result
}
Kevin Frei talks about exception handling performance cost in his speech "The Cost of C++ Exception Handling on Windows". (Under "Summary & Conclusions" there is one list item that says "[Exception handling performance cost is] not always measurable".)
There's no really good way to meassure that in code. You would need to use a a profiler.
This won't show you directly how much time is spent with exception handling but with a little bit of research you will find out which of the runtime methods deal with exceptions (for example for VC++.NET it's __cxx_exc[...]).
Add their times up and you have the overhead. In our project we used vTunes from Intel which works with both Visual C++ and gcc.
Edit: Well, if you just need a generic number that might work. Thought you had an actual application to profile where you can't just turn off exceptions.
Another note on exception handling performance: simple tests don't take caching into account. The try-code and the catch-code are both so small that everything fits in the instruction and data caches. But compilers may try to move the catch-code far away from the try-code, which reduces the amount of code to keep in cache normally, thus enhancing performance.
If you compare exception handling to traditional C-style return-value checking, this caching effect should be taken into account as well (the question is usually ignored in discussions).
Carl
Won't the answer depend on what cleanup has to happen as a result of a throw? If an excpetion is thrown that causes a whole load of objects to go out of scope up the stack, then that will add to the overhead.
In other words, I'm not sure if there is a an answer to the 3rd question that is independent of the specifics of the code.
Full details on how g++ handles exceptions is shown here. It describes it as being for the Itanium architecture, however the general techniques used are the same. It won't tell you exact overhead in terms of time, however you can glean what the rough code overhead will be.
Related
Here is a simple piece of code where a division by zero occurs. I'm trying to catch it :
#include <iostream>
int main(int argc, char *argv[]) {
int Dividend = 10;
int Divisor = 0;
try {
std::cout << Dividend / Divisor;
} catch(...) {
std::cout << "Error.";
}
return 0;
}
But the application crashes anyway (even though I put the option -fexceptions of MinGW).
Is it possible to catch such an exception (which I understand is not a C++ exception, but a FPU exception) ?
I'm aware that I could check for the divisor before dividing, but I made the assumption that, because a division by zero is rare (at least in my app), it would be more efficient to try dividing (and catching the error if it occurs) than testing each time the divisor before dividing.
I'm doing these tests on a WindowsXP computer, but would like to make it cross platform.
It's not an exception. It's an error which is determined at hardware level and is returned back to the operating system, which then notifies your program in some OS-specific way about it (like, by killing the process).
I believe that in such case what happens is not an exception but a signal. If it's the case: The operating system interrupts your program's main control flow and calls a signal handler, which - in turn - terminates the operation of your program.
It's the same type of error which appears when you dereference a null pointer (then your program crashes by SIGSEGV signal, segmentation fault).
You could try to use the functions from <csignal> header to try to provide a custom handler for the SIGFPE signal (it's for floating point exceptions, but it might be the case that it's also raised for integer division by zero - I'm really unsure here). You should however note that the signal handling is OS-dependent and MinGW somehow "emulates" the POSIX signals under Windows environment.
Here's the test on MinGW 4.5, Windows 7:
#include <csignal>
#include <iostream>
using namespace std;
void handler(int a) {
cout << "Signal " << a << " here!" << endl;
}
int main() {
signal(SIGFPE, handler);
int a = 1/0;
}
Output:
Signal 8 here!
And right after executing the signal handler, the system kills the process and displays an error message.
Using this, you can close any resources or log an error after a division by zero or a null pointer dereference... but unlike exceptions that's NOT a way to control your program's flow even in exceptional cases. A valid program shouldn't do that. Catching those signals is only useful for debugging/diagnosing purposes.
(There are some useful signals which are very useful in general in low-level programming and don't cause your program to be killed right after the handler, but that's a deep topic).
Dividing by zero is a logical error, a bug by the programmer. You shouldn't try to cope with it, you should debug and eliminate it. In addition, catching exceptions is extremely expensive- way more than divisor checking will be.
You can use Structured Exception Handling to catch the divide by zero error. How that's achieved depends on your compiler. MSVC offers a function to catch Structured Exceptions as catch(...) and also provides a function to translate Structured Exceptions into regular exceptions, as well as offering __try/__except/__finally. However I'm not familiar enough with MinGW to tell you how to do it in that compiler.
There's isn't a
language-standard way of catching
the divide-by-zero from the CPU.
Don't prematurely "optimize" away a
branch. Is your application
really CPU-bound in this context? I doubt it, and it isn't really an
optimization if you break your code.
Otherwise, I could make your code
even faster:
int main(int argc, char *argv[]) { /* Fastest program ever! */ }
Divide by zero is not an exception in C++, see https://web.archive.org/web/20121227152410/http://www.jdl.co.uk/briefings/divByZeroInCpp.html
Somehow the real explanation is still missing.
Is it possible to catch such an exception (which I understand is not a C++ exception, but a FPU exception) ?
Yes, your catch block should work on some compilers. But the problem is that your exception is not an FPU exception. You are doing integer division. I don’t know whether that’s also a catchable error but it’s not an FPU exception, which uses a feature of the IEEE representation of floating point numbers.
On Windows (with Visual C++), try this:
BOOL SafeDiv(INT32 dividend, INT32 divisor, INT32 *pResult)
{
__try
{
*pResult = dividend / divisor;
}
__except(GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
return FALSE;
}
return TRUE;
}
MSDN: http://msdn.microsoft.com/en-us/library/ms681409(v=vs.85).aspx
Well, if there was an exception handling about this, some component actually needed to do the check. Therefore you don't lose anything if you check it yourself. And there's not much that's faster than a simple comparison statement (one single CPU instruction "jump if equal zero" or something like that, don't remember the name)
To avoid infinite "Signal 8 here!" messages, just add 'exit' to Kos nice code:
#include <csignal>
#include <iostream>
#include <cstdlib> // exit
using namespace std;
void handler(int a) {
cout << "Signal " << a << " here!" << endl;
exit(1);
}
int main() {
signal(SIGFPE, handler);
int a = 1/0;
}
As others said, it's not an exception, it just generates a NaN or Inf.
Zero-divide is only one way to do that. If you do much math, there are lots of ways, like
log(not_positive_number), exp(big_number), etc.
If you can check for valid arguments before doing the calculation, then do so, but sometimes that's hard to do, so you may need to generate and handle an exception.
In MSVC there is a header file #include <float.h> containing a function _finite(x) that tells if a number is finite.
I'm pretty sure MinGW has something similar.
You can test that after a calculation and throw/catch your own exception or whatever.
I am learning exception models in c++. Following example showed interesting result for me
#include <cstdio>
struct A
{
A(int order) : m_order(order){}
~A(){printf("~A(%d)\n", m_order);}
int m_order;
};
void foo(void)
{
A a2 = 2;
int i = 0;
int j = 10 / i;
}
void foo1()
{
A a1 = 1;
foo();
}
void main()
{
try
{
foo1();
}
catch (...)
{
}
}
Result of execution of the program really depends on exception model.
For /EHa we have the output:
~A(2)
~A(1)
For /EHsc we have nothing.
As I understand, msvc c++ compiler internally uses SEH to support c++ exceptions. I thought that it will allow correctly call destructors of objects a1,a2 even in the case of hardware exceptions for both options (/EHa and /EHsc). But that example confuses me. It turns out that I should always use /EHa option to avoid possible memory leaks and corruptions in the case of hardware exceptions? But docs says that I should use /EHsc option whenever possible.
The problem with /EHa is that it's not guaranteed to catch every possible problem, yet it comes with significant overhead. /EHsc is a lot more efficient, and still catches every throw.
As an example, MSVC++ may execute /0.0 using x87, SSE or AVX instructions, and the resulting hardware exception can differ. I have no idea when /EHa catches that.
I'm trying to make a Python program that interfaces with a different crashy process (that's out of my hands). Unfortunately the program I'm interfacing with doesn't even crash reliably! So I want to make a quick C++ program that crashes on purpose but I don't actually know the best and shortest way to do that, does anyone know what to put between my:
int main() {
crashyCodeGoesHere();
}
to make my C++ program crash reliably
The abort() function is probably your best bet. It's part of the C standard library, and is defined as "causing abnormal program termination" (e.g, a fatal error or crash).
Try:
raise(SIGSEGV); // simulates a standard crash when access invalid memory
// ie anything that can go wrong with pointers.
Found in:
#include <signal.h>
Dividing by zero will crash the application:
int main()
{
return 1 / 0;
}
*((unsigned int*)0) = 0xDEAD;
Well, are we on stackoverflow, or not?
for (long long int i = 0; ++i; (&i)[i] = i);
(Not guaranteed to crash by any standards, but neither are any of the suggested answers including the accepted one since SIGABRT could have been caught anyway. In practice, this will crash everywhere.)
throw 42;
Just the answer... :)
assert(false); is pretty good too.
According to ISO/IEC 9899:1999 it is guaranteed to crash when NDEBUG is not defined:
If NDEBUG is defined [...] the assert macro is defined simply as
#define assert(ignore) ((void)0)
The assert macro is redefined according to the current state of NDEBUG each time that is included.
[...]
The assert macro puts diagnostic tests into programs; [...] if expression (which shall have a scalar type) is false [...]. It
then calls the abort function.
Since a crash is a symptom of invoking undefined behaviour, and since invoking undefined behaviour can lead to anything, including a crash, I don't think you want to really crash your program, but just have it drop into a debugger. The most portable way to do so is probably abort().
While raise(SIGABRT) has the same effect, it is certainly more to write. Both ways however can be intercepted by installing a signal handler for SIGABRT. So depending on your situation, you might want/need to raise another signal. SIGFPE, SIGILL, SIGINT, SIGTERM or SIGSEGV might be the way to go, but they all can be intercepted.
When you can be unportable, your choices might be even broader, like using SIGBUS on linux.
The answer is platform specific and depends on your goals. But here's the Mozilla Javascript crash function, which I think illustrates a lot of the challenges to making this work:
static JS_NEVER_INLINE void
CrashInJS()
{
/*
* We write 123 here so that the machine code for this function is
* unique. Otherwise the linker, trying to be smart, might use the
* same code for CrashInJS and for some other function. That
* messes up the signature in minidumps.
*/
#if defined(WIN32)
/*
* We used to call DebugBreak() on Windows, but amazingly, it causes
* the MSVS 2010 debugger not to be able to recover a call stack.
*/
*((int *) NULL) = 123;
exit(3);
#elif defined(__APPLE__)
/*
* On Mac OS X, Breakpad ignores signals. Only real Mach exceptions are
* trapped.
*/
*((int *) NULL) = 123; /* To continue from here in GDB: "return" then "continue". */
raise(SIGABRT); /* In case above statement gets nixed by the optimizer. */
#else
raise(SIGABRT); /* To continue from here in GDB: "signal 0". */
#endif
}
The only flash I had is abort() function:
It aborts the process with an abnormal program termination.It generates the SIGABRT signal, which by default causes the program to terminate returning an unsuccessful termination error code to the host environment.The program is terminated without executing destructors for objects of automatic or static storage duration, and without calling any atexit( which is called by exit() before the program terminates)function. It never returns to its caller.
I see there are many answers posted here that will fall into lucky cases to get the job done, but none of them are 100% deterministic to crash. Some will crash on one hardware and OS, the others would not.
However, there is a standard way as per official C++ standard to make it crash.
Quoting from C++ Standard ISO/IEC 14882 §15.1-7:
If the exception handling mechanism, after completing the
initialization of the exception object but before the activation of a
handler for the exception, calls a function that exits via an
exception, std::terminate is called (15.5.1).
struct C {
C() { }
C(const C&) {
if (std::uncaught_exceptions()) {
throw 0; // throw during copy to handler’s exception-declaration object (15.3)
}
}
};
int main() {
try {
throw C(); // calls std::terminate() if construction of the handler’s
// exception-declaration object is not elided (12.8)
} catch(C) { }
}
I have written a small code to demonstrate this and can be found and tried on Ideone here.
class MyClass{
public:
~MyClass() throw(int) { throw 0;}
};
int main() {
try {
MyClass myobj; // its destructor will cause an exception
// This is another exception along with exception due to destructor of myobj and will cause app to terminate
throw 1; // It could be some function call which can result in exception.
}
catch(...)
{
std::cout<<"Exception catched"<<endl;
}
return 0;
}
ISO/IEC 14882 §15.1/9 mentions throw without try block resulting in implicit call to abort:
If no exception is presently being handled, executing a
throw-expression with no operand calls std::terminate()
Others include :
throw from destructor: ISO/IEC 14882 §15.2/3
*( ( char* ) NULL ) = 0;
This will produce a segmentation fault.
This one is missing:
int main = 42;
This crashes on my Linux system, because string literals are stored in read only memory:
0[""]--;
By the way, g++ refuses to compile this. Compilers are getting smarter and smarter :)
What about stack overflow by a dead loop recursive method call?
#include <windows.h>
#include <stdio.h>
void main()
{
StackOverflow(0);
}
void StackOverflow(int depth)
{
char blockdata[10000];
printf("Overflow: %d\n", depth);
StackOverflow(depth+1);
}
See Original example on Microsoft KB
This is a more guaranteed version of abort presented in above answers.It takes care of the situation when sigabrt is blocked.You can infact use any signal instead of abort that has the default action of crashing the program.
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
sigset_t act;
sigemptyset(&act);
sigfillset(&act);
sigprocmask(SIG_UNBLOCK,&act,NULL);
abort();
}
This is the snippet provided by Google in Breakpad.
volatile int* a = reinterpret_cast<volatile int*>(NULL);
*a = 1;
int i = 1 / 0;
Your compiler will probably warn you about this, but it compiles just fine under GCC 4.4.3
This will probably cause a SIGFPE (floating-point exception), which perhaps is not as likely in a real application as SIGSEGV (memory segmentation violation) as the other answers cause, but it's still a crash. In my opinion, this is much more readable.
Another way, if we're going to cheat and use signal.h, is:
#include <signal.h>
int main() {
raise(SIGKILL);
}
This is guaranteed to kill the subprocess, to contrast with SIGSEGV.
int* p=0;
*p=0;
This should crash too. On Windows it crashes with AccessViolation and it should do the same on all OS-es I guess.
Although this question already has an accepted answer...
void main(){
throw 1;
}
Or... void main(){throw 1;}
int main(int argc, char *argv[])
{
char *buf=NULL;buf[0]=0;
return 0;
}
Writing to a read-only memory will cause segmentation fault unless your system don't support read-only memory blocks.
int main() {
(int&)main = 0;
}
I have tested it with MingGW 5.3.0 on Windows 7 and GCC on Linux Mint. I suppose that other compilers and systems will give a similar effect.
Or another way since we're on the band wagon.
A lovely piece of infinite recursion. Guaranteed to blow your stack.
int main(int argv, char* argc)
{
return main(argv, argc)
}
Prints out:
Segmentation fault (core dumped)
void main()
{
int *aNumber = (int*) malloc(sizeof(int));
int j = 10;
for(int i = 2; i <= j; ++i)
{
aNumber = (int*) realloc(aNumber, sizeof(int) * i);
j += 10;
}
}
Hope this crashes. Cheers.
int main()
{
int *p=3;
int s;
while(1) {
s=*p;
p++;
}
}
A stylish way of doing this is a pure virtual function call:
class Base;
void func(Base*);
class Base
{
public:
virtual void f() = 0;
Base()
{
func(this);
}
};
class Derived : Base
{
virtual void f()
{
}
};
void func(Base* p)
{
p->f();
}
int main()
{
Derived d;
}
Compiled with gcc, this prints:
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
You can use of assembly in your c++ code BUT INT 3 is only for x86 systems other systems may have other trap/breakpoint instructions.
int main()
{
__asm int 3;
return 0;
}
INT 3 causes an interrupt and calls an interrupt vector set up by the OS.
Use __builtin_trap() in GCC or clang, or __debugbreak() in MSVC. Not handling these breakpoints/traps will lead to an unhandled breakpoint exception/crash.
Other suggestions that use abort() or exit(): those may be handled by other threads, making it more difficult to see the stack of the thread that propagated the crash.
#include <thread>
void intentionalCrash()
{
auto noop = [](){return;};
// Thread t1 is in a joinable state.
// When program returns t1 will be out of scope.
// Destructing a joinable thread creates a crash.
std::thread t1(noop);
}
int main()
{
intentionalCrash();
return 0;
}
Simple buffer overflow code that will cause the program to crash
int main()
{
int n[0];
n[2] = 0;
}
I am trying to port some code using VC++'s try-except statement to MinGW:
bool success = true;
__try {
//...
} __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode())
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
success = false;
_resetstkoflw();
}
return success;
Is it possible to write code that catches a stack overflow exception using MinGW g++?
You would need to manually call the Windows API functions which register exception handling; namely, AddVectoredExceptionHandler. Note that by using MinGW which does not respect SEH exceptions, throwing any SEH exception or attempting to catch any such exception will result in undefined behavior, because the normal C++ stack unwinding semantic isn't done. (How does Windows know to nuke all those std::strings on the stack?)
You would also need to call RemoveVectoredExceptionHandler at the end of the time you want that SEH exception handler to be called.
Generally MinGW is lacking in support of Windows features like SEH and COM. Any reason you're trying to use that instead of MSVC++ (given that both compilers are free?)
This isn't well known, but the header file <excpt.h> in MinGW and MinGW-w64 provides macros __try1 and __except1 to produce gcc inline assembly for handling exceptions. These macros are not documented and are not easy to use. It gets worse. The x86_64 editions of __try1 and __except1 aren't compatible with the 32-bit editions. They use different callbacks with different arguments and different return values.
After a few hours, I almost had working code on x86_64. I needed to declare a callback with the same prototype as _gnu_exception_handler in MinGW's runtime. My callback was
long CALLBACK
ehandler(EXCEPTION_POINTERS *pointers)
{
switch (pointers->ExceptionRecord->ExceptionCode) {
case EXCEPTION_STACK_OVERFLOW:
return EXCEPTION_EXECUTE_HANDLER;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
And my try-except code was
__try1 (ehandler) {
sum = sum1to(n);
__asm__ goto ( "jmp %l[ok]\n" :::: ok);
} __except1 {
printf("Stack overflow!\n");
return 1;
}
ok:
printf("The sum from 1 to %u is %u\n", n, sum);
return 0;
It was working until I enabled optimization with gcc -O2. This caused assembler errors so my program no longer compiled. The __try1 and __except1 macros are broken by an optimization in gcc 5.0.2 that moves functions from .text to a different section.
When the macros did work, the control flow was stupid. If a stack overflow happened, the program jumped through __except1. If a stack overflow didn't happen, the program fell through __except1 to the same place. I needed my weird __asm__ goto to jump to ok: and prevent the fall-through. I can't use goto ok; because gcc would delete __except1 for being unreachable.
After a few more hours, I fixed my program. I copied and modified the assembly code to improve the control flow (no more jump to ok:) and to survive gcc -O2 optimization. This code is ugly, but it works for me:
/* gcc except-so.c -o except-so */
#include <windows.h>
#include <excpt.h>
#include <stdio.h>
#ifndef __x86_64__
#error This program requires x86_64
#endif
/* This function can overflow the call stack. */
unsigned int
sum1to(unsigned int n)
{
if (n == 0)
return 0;
else {
volatile unsigned int m = sum1to(n - 1);
return m + n;
}
}
long CALLBACK
ehandler(EXCEPTION_POINTERS *pointers)
{
switch (pointers->ExceptionRecord->ExceptionCode) {
case EXCEPTION_STACK_OVERFLOW:
return EXCEPTION_EXECUTE_HANDLER;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
int main(int, char **) __attribute__ ((section (".text.startup")));
/*
* Sum the numbers from 1 to the argument.
*/
int
main(int argc, char **argv) {
unsigned int n, sum;
char c;
if (argc != 2 || sscanf(argv[1], "%u %c", &n, &c) != 1) {
printf("Argument must be a number!\n");
return 1;
}
__asm__ goto (
".seh_handler __C_specific_handler, #except\n\t"
".seh_handlerdata\n\t"
".long 1\n\t"
".rva .l_startw, .l_endw, ehandler, .l_exceptw\n\t"
".section .text.startup, \"x\"\n"
".l_startw:"
:::: except );
sum = sum1to(n);
__asm__ (".l_endw:");
printf("The sum from 1 to %u is %u\n", n, sum);
return 0;
except:
__asm__ (".l_exceptw:");
printf("Stack overflow!\n");
return 1;
}
You might wonder how Windows can call ehandler() on a full stack. All those recursive calls to sum1to() must remain on the stack until my handler decides what to do. There is some magic in the Windows kernel; when it reports a stack overflow, it also maps an extra page of stack so that ntdll.exe can call my handler. I can see this in gdb, if I put a breakpoint on my handler. The stack grows down to address 0x54000 on my machine. The stack frames from sum1to() stop at 0x54000, but the exception handler runs on an extra page of stack from 0x53000 to 0x54000. Unix signals have no such magic, which is why Unix programs need sigaltstack() to handle a stack overflow.
You might want to look into LibSEH for adding Structured Exception Handling compatibility for MinGW.
MinGW doesn't support the keywords for structured exceptions; but, as Billy O'Neal says in his answer, you can call certain native functions to get the same effect.
The question is whether you want the same effect. I strongly believe that structured exceptions are a mistake. The list of structured exceptions that the operating system will tell you about include things like "tried to divide an integer by 0," "couldn't use the HANDLE parameter passed to a function," "tried to execute an illegal machine code instruction," and "tried to access memory without permission to do so." You really can't do anything intelligent about these errors, but structured exceptions give you the opportunity to (1) claim that you have and (2) allow the program to hobble along a little longer. It's far better to find out why the code tried to divide by 0, passed an invalid HANDLE parameter, tried to access memory without permission to do so, etc. and fix the code to never do that.
There is an argument that you could use structured exceptions to detect problems, display a dialog box, and exit. I'm not sure how this is better than letting the operating system display a dialog box and exit the program (especially if the operating system sends you a minidump in the process), which is the default behavior for unhandled exceptions.
Some errors aren't recoverable.
I have a C++ application that calls SQLite's (SQLite is in C) sqlite3_exec() which in turn can call my callback function implemented in C++. SQLite is compiled into a static library.
If an exception escapes my callback will it propagate safely through the C code of SQLite to the C++ code calling sqlite3_exec()?
My guess is that this is compiler dependent. However, throwing an exception in the callback would be a very bad idea. Either it will flat-out not work, or the C code in the SQLite library will be unable to handle it. Consider if this is some code in SQLite:
{
char * p = malloc( 1000 );
...
call_the_callback(); // might throw an exception
...
free( p );
}
If the exception "works", the C code has no possible way of catching it, and p will never be freed. The same goes for any other resources the library may have allocated, of course.
There is already a protocol for the callback to abort the API call. From the docs:
If an sqlite3_exec() callback returns
non-zero, the sqlite3_exec() routine
returns SQLITE_ABORT without invoking
the callback again and without running
any subsequent SQL statements.
I'd strongly recommend you use this instead of an exception.
SQLite is expecting you to return a SQLITE_ABORT on error and a 0 return code for no error. So you ought to wrap all your C++ callback in a try catch. Then in the catch return a SQLite SQLITE_ABORT error code, otherwise a zero.
Problems will occur if you bypass returning through SQLite as it will not free up/complete whatever code it does after you return back from your callback. This will cause untold problems potentially some of which maybe very obscure.
That was a really interesting question and I tested it out myself out of curiosity. On my OS X w/ gcc 4.2.1 the answer was YES. It works perfectly. I think a real test would be using gcc for the C++ and some other (MSVC?, LLVM?) for the C part and see if it still works.
My code:
callb.h:
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*t_callb)();
void cfun(t_callb fn);
#ifdef __cplusplus
}
#endif
callb.c:
#include "callb.h"
void cfun(t_callb fn) {
fn();
}
main.cpp:
#include <iostream>
#include <string>
#include "callb.h"
void myfn() {
std::string s( "My Callb Except" );
throw s;
}
int main() {
try {
cfun(myfn);
}
catch(std::string s) {
std::cout << "Caught: " << s << std::endl;
}
return 0;
}
If your callback called from sqlite is from the same thread from which you called sqlite3_exec() a throw somewhere in the callstack should be caught by a higher level catch.
Testing this yourself should be straightforward, no?
[edit]
After digging a little more myself I found out that the C++ standard is somewhat vague on what the behavior a c++ function called from c should have when throwing an exception.
You should definitely use the error handling mechanism the API expects. Otherwise you'll mostly the API itself in an undefined state and any further calls could potentially fail/crash.
Not a single answer mentioning building your C library with -fexceptions? Throw in a -fno-omit-framepointer and you are good to go. This works even across a shared library (written in C), as long as you throw from your main program, and catch in your main program again.