Reputation: 170469
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()?
Upvotes: 31
Views: 4118
Reputation: 519
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.
Upvotes: 0
Reputation: 4390
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;
}
Upvotes: 1
Reputation: 8830
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.
Upvotes: 10
Reputation:
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.
Upvotes: 29
Reputation: 255
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.
Upvotes: 0
Reputation: 941277
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.
Upvotes: 14