Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is a longjmp from a C library into C++ code safe?

Tags:

c++

c

setjmp

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?

like image 553
Sam Coutteau Avatar asked Sep 13 '25 00:09

Sam Coutteau


2 Answers

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"
    }
    // ...
}
like image 70
Adrian McCarthy Avatar answered Sep 14 '25 12:09

Adrian McCarthy


The problem with longjmp into C++ is the same as the problem with longjmp out of C++: some destructors might not get run when they should have. In your example code, the vector<int> will probably be leaked if the library calls longjmp.

If you control all the C++, you can arrange things so the longjmp never bypasses any destructors. Adrian McCarthy's answer demonstrates how.

like image 33
zwol Avatar answered Sep 14 '25 14:09

zwol