Will C++ exceptions safely propagate through C code?

倾然丶 夕夏残阳落幕 提交于 2019-12-17 06:13:00

问题


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()?


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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;
}



回答5:


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.



来源:https://stackoverflow.com/questions/2101390/will-c-exceptions-safely-propagate-through-c-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!