In C++, when working with a C library which uses longjmp
for error handling. Is it safe to have the C code jump into C++ using setjmp
. I know that jumping away from C++ code can lead to issues with destructors not being called but is the same true for jumping into C++ code.
Pseudo code of usage
if( setjmp( lib_get_jmpbuf() ) )
{
throw "exception";
}
if( lib_question() )
{
std::vector<int> stuff(5);
lib_could_jump_way(stuff.data(), stuff.size());
}
If this is not safe, how do you interface with such C libraries safely?
As your sample is written, the library code could jump back into a different scope than the one from which it's called. And since the stuff
vector is in that scope, I wouldn't expect it to be destroyed when the exception is thrown. (Stack unwinding for exception propagation is complex, so I could be wrong.)
At a minimum, I'd hoist stuff
above the setjmp()
.
A better idea might be to create a C wrapper function for each library API that might throw. The wrapper should be responsible for the setjmp
. Whether the library function returns or jumps, the wrapper should convert the result to a regular return. The C++ code then would call the wrapper function and either proceed or throw based on the return value.
// wrapper.c (should be compiled as C, not C++)
#include "wrapper.h"
int lib_could_jump_wrapper(int *stuff, size_t size) {
if (setjmp(lib_get_jmp_buf())) {
return LIBRARY_JUMPED;
}
lib_could_jump_way(stuff, size);
return LIBRARY_RETURNED;
}
// wrapper.h
#define LIBRARY_RETURNED 0
#define LIBRARY_JUMPED 1
#ifdef __cplusplus__
extern "C" {
#endif
int lib_could_jump_wrapper(int *stuff, size_t size);
#ifdef __cplusplus__
}
#endif
// Your C++ code:
#include "wrapper.h"
// ...
if (lib_question()) {
std::vector<int> stuff;
if (lib_could_jump_wrapper(stuff.data(), stuff.size()) == LIBRARY_JUMPED) {
throw "exception"
}
// ...
}