Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing exceptions across a C API boundary

I am writing a library in C++ which uses an older C API. The client of my library can specify callback functions, which are indirectly called through my library which is called through the C API. This means that all exceptions in the client callbacks must be handled.

My question is this: how can I catch the exception on one side of the boundary and re-throw it once the C API boundary has been recrossed and the execution is back in C++ land so that the exception can be handled by client code?

like image 821
Seth Carnegie Avatar asked Feb 12 '12 19:02

Seth Carnegie


2 Answers

With C++11 we could use:

std::exception_ptr active_exception;

try
{
    // call code which may throw exceptions
}
catch (...)
{
    // an exception is thrown. save it for future re-throwing.
    active_exception = std::current_exception();
}

// call C code
...

// back to C++, re-throw the exception if needed.
if (active_exception)
    std::rethrow_exception(active_exception);

Before C++11 these can still be used via Boost Exception.

like image 134
kennytm Avatar answered Nov 13 '22 11:11

kennytm


Some environments support this more or less directly.

For instance, if you enable structured exception handling and C++ exceptions through the /EH compiler switch, you can have C++ exceptions implemented over Microsoft's structured exception handling ("exceptions" for C). Provided these options are set when compiling all your code (the C++ at each end and the C in the middle) stack unwinding will "work".

However, this is almost always a Bad Idea (TM). Why, you ask? Consider that the piece of C code in the middle is:

WaitForSingleObject(mutex, ...);
invoke_cxx_callback(...);
ReleaseMutex(mutex);

And that the invoke_cxx_callback() (....drum roll...) invokes your C++ code that throws an exception. You will leak a mutex lock. Ouch.

You see, the thing is that most C code is not written to handle C++-style stack unwinding at any moment in a function's execution. Moreover, it lacks destructors, so it doesn't have RAII to protect itself from exceptions.

Kenny TM has a solution for C++11 and Boost-based projects. xxbbcc has a more general, albeit more tedious solution for the general case.

like image 3
André Caron Avatar answered Nov 13 '22 11:11

André Caron