programing

C++ 예외는 C 코드를 통해 안전하게 전파됩니까?

javajsp 2023. 10. 31. 20:28

C++ 예외는 C 코드를 통해 안전하게 전파됩니까?

저는 SQLite의 (SQLite는 C에 있음) sqlite3_exec()를 호출하는 C++ 애플리케이션을 가지고 있는데, 이것은 다시 C++에서 구현된 제 콜백 함수를 호출할 수 있습니다.SQLite는 정적 라이브러리로 컴파일됩니다.

예외가 발생하면 SQLite의 C 코드를 통해 sqlite3_exec()라는 C++ 코드로 안전하게 전파됩니까?

이것은 컴파일러에 의존적인 것 같습니다.하지만 콜백에서 예외를 두는 것은 매우 나쁜 생각일 것입니다.플랫 아웃이 되지 않거나 SQLite 라이브러리의 C 코드가 처리할 수 없습니다.SQLite의 코드가 무엇인지 고려해 보십시오.

{
  char * p = malloc( 1000 );
  ...
  call_the_callback();  // might throw an exception
  ...
  free( p );
}

예외가 "작동"하는 경우 C 코드는 이를 잡을 수 있는 방법이 없으며 p는 결코 자유롭지 않습니다.물론 도서관이 할당했을 수도 있는 다른 자원들도 마찬가지입니다.

API 호출을 중단하기 위한 콜백 프로토콜이 이미 있습니다.문서에서:

sqlite3_exec() 콜백이 0이 아닌 경우 sqlite3_exec() 루틴은 콜백을 다시 호출하지 않고 이후 SQL 문을 실행하지 않고 SQLITE_ABORT를 반환합니다.

예외가 아니라 이것을 사용하는 것을 강력히 추천합니다.

SQLite에서 오류 시 SQLITE_ABORT를 반환하고 오류 없이 0 반환 코드를 반환해야 합니다.따라서 당신은 당신의 모든 C++ 콜백을 트라이 캐치로 포장해야 합니다.그런 다음 캐치에서 SQLite SQLITE_ABORT 오류 코드를 반환하고 그렇지 않으면 0을 반환합니다.

콜백에서 돌아온 후 어떤 코드를 사용해도 해제/완료되지 않으므로 SQLite를 통해 우회 복귀할 경우 문제가 발생합니다.이로 인해 잠재적으로 알려지지 않은 문제가 발생할 수 있습니다.

그것은 정말 흥미로운 질문이었고 저는 호기심으로 직접 시험해 보았습니다.내 OS X w/gcc 4.2.1에서 YES라고 답했습니다.완벽하게 작동합니다.실제 테스트는 C++에 gcc를 사용하고 C 부분에 다른 것(MSVC?, LLVM?)을 사용하는 것이 좋을 것 같습니다.

내 코드:

호출 b.h:

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*t_callb)();
void cfun(t_callb fn);

#ifdef __cplusplus
}
#endif

호출 b.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;
}

sqlite에서 호출한 콜백이 sqlite3_exec()에서 호출한 스레드와 동일한 스레드에서 호출한 경우 콜스택의 어딘가에 던지면 상위 레벨 캐치가 발생합니다.

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.

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.

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