How to catch C++ exceptions in C? [duplicate] - c++

I am developing C++ component dll that can be used by C or C++ applications.
The exposed dll functions are as follows
#include <tchar.h>
#ifdef IMPORT
#define DLL __declspec(dllimport)
#else
#define DLL __declspec(dllexport)
#endif
extern "C" {
DLL bool __cdecl Init();
DLL bool __cdecl Foo(const TCHAR*);
DLL bool __cdecl Release();
}
the internal implementation of these functions are C++ classes which are not exposed, I assume using this style the dll can be used either in C or C++ apps.
The problem is I do not handle any type of c++ exception (i.e. bad_alloc) and I left this stuff to the caller (the higher layer).
After much debate with my colleagues that I should catch all the exceptions and return error code or at least false because in case of C application it can not handle C++ exceptions? is that true? and what I should do in general? is there a rule of thumb for handling exeptions if you are developing component that will be used by other system.

C doesn't have exceptions, therefore in general you should catch all exception and return an error code and/or provide a function that returns the information about the last error.

If this is Windows using MSVC then yes you can catch exceptions in C but you can't catch them that well. C++ exceptions are fed through the OS ABI's Structured Exception Handling mechanism, and Microsoft have a __try, __except, __finally C extension to handle OS structured exceptions. Note that these include access violations, divide-by-zero, etc. that you'd normally want to terminate your program and log a bug report. You can identify C++ exceptions by code 0xE04D5343 (4D 53 43 = "MSC") and throw the rest on.
That all said, you probably don't want to be throwing exceptions across a DLL boundary, and certainly not if you're only exposing a C API.

As a general rule, you should never allow C++ exceptions to propagate beyond a module's boundary. This is because the C++ standard does not specify how exception propagation has to be implemented, and as such this is compiler (and compiler flags) and operating system dependent. You cannot guarantee that the code calling your module will be compiled with the same compiler with the same compiler flags as your module. In fact, as you're demonstrating with this question is that you cannot guarantee that code calling your module will be written in the same language.
For more details, please refer to Item 62 in C++ Coding Standards by Sutter and Alexandrescu.

Ok, since it was asked for:
C++ example code:
#include <typeinfo>
#include <exception>
extern "C" {
void sethandler(void (*func)(void)) { std::set_terminate(func); }
int throwingFunc(int arg) {
if (arg == 0)
throw std::bad_cast();
return (arg - 1);
}
}
C example code:
#include <stdio.h>
extern int throwingFunc(int arg);
extern void sethandler(void (*func)(void));
void myhandler(void)
{
printf("handler called - must've been some exception ?!\n");
}
int main(int argc, char **argv)
{
sethandler(myhandler);
printf("throwingFunc(1) == %d\n", throwingFunc(1));
printf("throwingFunc(-1) == %d\n", throwingFunc(-1));
printf("throwingFunc(0) == %d\n", throwingFunc(0));
return 0;
}
When I compile these two, link them together and run this (Ubuntu 10.04, gcc 4.4.5, x64), I get:
$ ./xx
throwingFunc(1) == 0
throwingFunc(-1) == -2
handler called - must've been some exception ?!
Aborted
So while you can catch exceptions from C, that's hardly sufficient - because C++ runtime behaviour after std::terminate() is undefined, and because the handler gets no status information whatsoever (to distiguish exception types and/or sources). The handler cannot clean up anything.
Btw, I've deliberately chosen std::bad_cast() as exception type in this example. This is because throwing that illustrates a difference in behaviour between std::set_unexpected() and std::set_terminate() - the unexpected handler will get called for all non std::bad_* exceptions, while in order to catch standard exceptions, a terminate handler is required ... see the dilemma ? The harness is too wide to be of practical use :(

Only propagate exceptions to the caller if the caller is designed to handle them. I guess in your case terminate() will be called immediately once any exception escapes C++ code because from the point of C++ runtime that exception has not been handled.
The same situation arises in COM servers design - the clients can be in whatever language/technology. The rul is that no exceptions should escape COM server methods - all exceptions must be caught and translated in HRESULT and (optionally) IErrorInfo. You should do similarly in your situations.
In case C code is sandwiched between two layers of C++ code propagating exceptions to C code is still a very bad idea.

Related

When WINAPI calls my code and an exception is thrown, should I catch it and return an HRESULT instead?

I have implemented IThumbnailProvider which gets compiled to a dll and then registered using regsvr32.
Within the code, I make use of STL containers such as std::vector:
std::vector<double> someRGBAccumulatorForDownsamplingToThumbnail = std::vector<double>(1234567);
Because the STL containers are largely built around RAII, there is no null-checking for failed memory allocations. Instead, the above code will throw an exception in an out-of-memory scenario. When this happens, should I catch this exception to return an HRESULT (context: implementation of GetThumbnail) instead?
try {
// ...
} catch (bad_alloc& ex) {
return E_OUTOFMEMORY;
}
Or can WINAPI safely handle me allowing the exception to "bubble up"?
I am asking because I am reading that WINAPI is C-based, and that C does not have exceptions.
IThumbnailProvider is a COM interface. The Component Object Model is a language-agnostic protocol that describes (among others) the binary contract between clients and implementers of interfaces. It establishes a boundary (the Application Binary Interface, ABI) with clear rules1.
Since the protocol is language-agnostic, things that are allowed to cross the ABI are limited to the least common denominator. It's ultimately slightly less than what C function calls support. Any language-specific construct (such as C++ exceptions) must not cross the ABI.
When implementing a COM interface in C++ you have to make sure that C++ exceptions never cross the ABI. The bare minimum you could do is mark all interface methods as noexcept:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
// ...
}
While that meets all requirements of the COM contract, it's generally not desirable to have an uncaught exception bring down the entire process in which the COM object lives.
A more elaborate solution would instead catch all exceptions and turn them into HRESULT error codes (see Error Handling in COM), similar to what the code in question does:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
} catch(...) {
return E_FAIL;
}
}
Again, this is perfectly valid, though any COM developer dreads seeing the 0x80004005 error code, that's semantically equivalent to "something went wrong". Hardly useful when trying to diagnose an issue.
A more helpful implementation would attempt to map certain well-known C++ exception types to standard HRESULT values (e.g. std::bad_alloc -> E_OUTOFMEMORY, or std::system_error to the result of calling HRESULT_FROM_WIN32). While one could manually implement a catch-cascade on every interface method implementation, there are libraries that do it for you already. The Windows Implementation Library (WIL) provides exception guards for this purpose, keeping the details out of your code.
The following is a possible interface method implementation using the WIL:
HRESULT MyThumbnailProvider::GetThumbnail(UINT, HBITMAP*, WTS_ALPHATYPE*) noexcept {
try {
// ...
}
CATCH_RETURN();
}
As an aside, I've kept the noexcept specifiers on the latter two implementations as a defensive measure only; they are not strictly required, but keep the interface valid in case the implementation changes in the future in a way that would allow a C++ exception to escape.
1 I'm not aware of an official document that spells out those rules. We have to assume that the compiler is the specification. Incidentally, Microsoft's C and C++ compiler do not agree, which the Direct2D team found out the hard way.

Catching fortran runtime errors and signals in C++ binding

I would like to be able to catch a terminating Fortran runtime errors in a C++ binding.
I have a legacy F90 code to bind to and expect all kind of errors e.g. numerical, IO etc.
I managed to handle STOP according to:
Intercepting Fortran STOP from C++
and able to throw/catch exception for this case in the C++ code.
I got some understanding 'Signal Handling in Fortran' at
https://www.sharcnet.ca/help/images/4/42/Fortran_Signal_Handling.pdf
However I do not manage with this, an example for f90 fortran would be very helpful.
For example trying to open a non existant file in the fortran subroutine would give a runtime error, and the C++ code terminates:
open (unit=13,FILE="fnameBAD",status="old",action="read",position="rewind")
Fortran runtime error: Cannot open file 'fnameBAD': No such file or directory
I would like to be able to catch this and other runtime errors using signals.
This won't work, at least for GFortran. When then OPEN statement fails, the GFortran runtime library will shut itself down, and only finally is the signal generated. So by the time you can catch the signal in the signal handler, libgfortran has already shut itself down (including closing all open files).
The solution, as Vladimir F says in a comment, is to catch the error in the OPEN statement with the iostat= specifier.
I've implemented something like that for unittesting C-bindings for a Fortran code from C/C++ to catch abort calls using setjmp and longjmp (essentially the same as an answer in the already linked question):
#include <setjmp.h>
#include <signal.h>
jmp_buf jmp_env;
void on_sigabrt(int signum)
{
(void) signum; // silence "unused parameter" warning
longjmp(jmp_env, 1);
}
void func()
{
if (setjmp(jmp_env) == 0) {
signal(SIGABRT, &on_sigabrt);
/* YOUR CALLS HERE */
} else {
/* ERROR HANDLING GOES HERE */
}
}
The problem #janneb already described remains: Even while longjmp should restore the stack to the point of the setjmp, it does not guarantee that all internal state in the Fortran runtime library is restored.
In fact, both books Modern Fortran: Style and Usage (rule 182) and The Fortran 2003 Handbook (15.6.4) mention that Fortran code should not be wrapped in between setjmp and longjmp.
On the other hand, there are compiler vendors which explicitly provide setjmp/longjmp wrappers (Oracle for example), as well as several projects with a similar focus:
funwind
zsvjmp
That being said, it is likely a better (and more portable) approach to use proper error handling using the iostat attribute whenever possible, as others already commented.

object is not destroyed after catching exception in mixed C and C++ code programming

I am writing a program using mixing c and c++, and I meet a problem about object destruction in c++ exception handler. I wrote a simple case to reproduce the problem.
main.cpp
#include <iostream>
extern "C" void test(void(*f)(void));
struct foo {
~foo() {
std::cout << "foo destruction" << std::endl;
}
};
void error_handler(void) {
throw 1;
}
int main() {
try {
foo f;
test(error_handler);
} catch (...) {
}
}
test.c
void test(void(*handler)(void)) {
handler();
}
When I build this in Visual Studio 2015 and Visual Studio 2017, the foo's destructor was not called. But when I test it using gcc 5.4, the foo's destructor works fine.
Is it possible to throw C++ exception in C code through calling function pointer (which pointer to the function implemented in cpp code)? Is the code above illegal or it's just an msvc bug?
The Windows Exception mechanism is explicitly designed to be able to run destructors and perform finally type cleanup even in the presence of exceptions and similar from other languages.
So what you're asking should work fine on windows - its what its designed to do.
However, you need to explicitly enable this in Visual Studio. By default, visual studio sets up C++ code with /EHsc exception model which explicitly assume that extern "C" functions do not throw or pass through exceptions. This is an optimisation, and generally a good one.
However, if you need to assume that extern "C" functions do throw or pass through exceptions then you need to change your exception model. You probably want /EHs.
However, I'd recommend reading up on the ramifications of this before you change it here.
Edit: Whether to use this functionality or not is debatable. Generally with exceptions (and other similar mechanisms) all code on the stack between the thrower and caller need to be exception safe. If you own the code then this is fine, if there's things like windows callbacks or other libraries on the stack then you need to find a guarantee that this is ok. And in general for windows internal code its not.
Throwing exceptions across language boundaries always leaves program in inconsistent state. Stack unwinding performed in case of C++ exception thrown is guaranteed to work only on (binary compatible) C++ stack frames. C language does not even have a concept of exceptions. Even if stack unwinding manages to unwind C stack frames it will not perform any cleanup for them. So any callback function passed to C code should be declared as noexcept and handle error in some manner that does not involve throwing of exception across language boundary:
void error_handler(void) noexcept {
try
{
throw 1;
}
catch(…)
{
// TODO convert to error code or store for later using exception_ptr
}
}

C++ exception handling in C codes

When we write a program in C, it is possible that we will call some libraries that were wrote in C++ but had a C interface. Then it may happen that when we call these libraries, a C++ exception will occur. So my question is how we can handle this situation. I am more interested in this problem from a C++ developer's perspective. Suppose I am developing a C++ library that will be invoked by a C program, should I stop using exception and instead return error codes? Another situation is that if I have already a fully developed C++ library that uses exception, how can I transfer this library in a quick way that will only use error returning method?
You have to catch all exceptions on the C++ side and convert them to appropriate error returns in C, which may include specific error codes where appropriate. This doesn't mean that you stop using exceptions — you can still use them in C++ — but you can't expose them to C, they become an implementation detail.
A typical wrapper can be structured as follows:
// thingy-wrapper.h, typically included from C code:
#ifdef __cplusplus
extern "C" {
#endif
// create a typedef visible to C that doesn't expose the layout of
// the implementation.
typedef void *thingy_t;
// wrapper for std::string Thingy::get_name()
char *thingy_get_name(thingy_t t);
#ifdef __cplusplus
}
#endif
// thingy-wrapper.cpp, implements the wrapper, compiled with C++:
#include <thingy-wrapper.h>
#include <thingy.hpp> // declares Thingy class
char *thingy_get_name(thingy_t t_)
{
try {
Thingy& t = *static_cast<Thingy*>(t_);
std::string name = t.get_name();
return strdup(name.c_str());
}
catch(...) {
return NULL;
}
}
In this simple example, the caller of thingy_get_name can detect that an error occurred, but cannot find out the details of the error. A more realistic example would catch specific exceptions, and set a last_error variable to an error code or message before returning NULL. ... would only be caught as a last resort, and would set last_error to a generic UNKNOWN_ERROR value. A separate API for querying the last error, such as thingy_last_error(), would be available for the more careful callers of thingy_get_name().
The separation between error and non-error results enables code that doesn't care about the cause of errors to simply check if it received NULL, while allowing more conscientious code to properly propagate or report the error. If your library is multi-threaded, make sure that last_error uses thread-local storage.
Then it may happen that when we call these libraries, a C++ exception will occur. So my question is how we can handle this situation.
The C code cannot handle this situation. C code cannot deal with C++ exceptions.
Suppose I am developing a C++ library that will be invoked by a C program, should I stop using exception and instead return error codes?
No. If you want the C++ library to be consumed by C++ code you should use native C++ error handling. Which means exceptions.
However, the interface that you expose to the C code must not throw exceptions. Typically this means writing an adaptor layer that catches exceptions raised by the C++ library, and converts them into error codes to be consumed by the C code.
Another situation is that if I have already a fully developed C++ library that uses exception, how can I transfer this library in a quick way that will only use error returning method?
There's really no shortcut here. You have to write the adaptor that converts C++ exceptions into C error codes. You'll be writing an adaptor anyway if you want the library to expose interfaces for both C and C++ consumers. So the aspect of error handling is just another thing to take care of with this adaptor.
Exception are not caught in C so if you want to catch them then in your C code or your C++ code you have to write the wrappers very carefully.
Also make sure that in your C++ functions you have your functions declared as:
extern "C"
You may also check How to mix C and C++

C++, __try and try/catch/finally

I'm wondering a bit about C++ try/catch/finally blocks. I've seen these commands with two underscores like __try. But MVSC 2010 projects also run without the underscores. So when do you need these underscores?
On Windows, exceptions are supported at the operating system level. Called Structured Exception Handling (SEH), they are the rough equivalent to Unix signals. Compilers that generate code for Windows typically take advantage of this, they use the SEH infrastructure to implement C++ exceptions.
In keeping with the C++ standard, the throw and catch keywords only ever throw and catch C++ exceptions. The corresponding SEH exception code for the MSVC compiler is 0xe06d7363. The last 3 bytes are the ASCII code for "msc".
Unifying it with the operating system support also means that C++ destructors will be called during stack unwinding for an SEH exception. The code that does the unwinding is inside Windows and treats the SEH raised by a throw the exact same way as any SEH. However, the Microsoft compiler has an optimization that tries to avoid generating the code required that ensures that destructors are called in all cases. If it can prove that there's no throw statement inside the scope block that controls the object's lifetime then it skips the registration code. This is not compatible with asynchronous SEH exceptions, you should use the /EHa compile option to suppress this optimization if you intend to catch SEH exceptions.
There are a lot of SEH exception types. The ones that can be generated by the operating system are listed in the ntstatus.h SDK header file. In addition, you might interop with code that uses SEH to implement their own exception handling, they will use their own exception code. Like .NET, managed exceptions use the 0xe0434f4d ("com") exception code.
To catch SEH exceptions in a C++ program, you must use the non-standard __try keyword. The __except keyword is analogous to the C++ catch keyword. It has more capabilities, you specify an exception filter expression that determines whether or not an active exception should be caught. Anything is possible, but you typically only look at the passed exception information to see if you're interested in handling it. The __finally keyword lets you write code that runs after the exception is handled. No equivalent for that in C++ but not uncommon in other languages.
All of this is fairly poorly documented as pointed out in the comments. The proof is in the pudding. Here's an example program that you can play with. It demonstrates how SEH exceptions still allows for C++ destructors to be called, provided you compile with /EHa and how C++ exceptions are implemented on top of SEH. MSVC compiler required, run with Ctrl+F5 to avoid the debugger being helpful:
#include "stdafx.h"
#include <windows.h>
#include <iostream>
// NOTE: the value of the C/C++, Code Generation, Enable C++ Exceptions setting in important
// Try it both with /EHsc (the default) and /EHa to see the difference
class Example {
public:
~Example() { std::cout << "destructed" << std::endl; }
};
int filterException(int code, PEXCEPTION_POINTERS ex) {
std::cout << "Filtering " << std::hex << code << std::endl;
return EXCEPTION_EXECUTE_HANDLER;
}
void testProcessorFault() {
Example e;
int* p = 0;
*p = 42;
}
void testCppException() {
Example e;
throw 42;
}
int main()
{
__try {
testProcessorFault();
}
__except(filterException(GetExceptionCode(), GetExceptionInformation())) {
std::cout << "caught" << std::endl;
}
__try {
testCppException();
}
__except(filterException(GetExceptionCode(), GetExceptionInformation())) {
std::cout << "caught" << std::endl;
}
return 0;
}
Output:
Filtering c0000005
destructed
caught
Filtering e06d7363
destructed
caught
__try / __except is for catching SEH (windows generated errors) not for catching general exceptions.
try / catch is what the C++ standard specifies for handling general C++ exceptions.
For the standard C++ code you write you should always use try/ catch and not __try / __except
Also, finally is not C++ Standard specified construct, It works for you because it is a Microsoft compiler extension.
__try/__except is Microsoft specific If you want your code to be compilable with other compilers (for examplec g++) (or) in another OS avoid using them, and stick with the standard try/catch statements