Sandboxing exceptions (of external libraries & the std::lib) - c++

I have watched Mike Acton's talk on Data-Oriented Design and C++.
As he stated at 8min30sec that they don't use exceptions, they cannot force it to be off on third party libraries. Therefore they "sandbox around" these libraries.
My questions are:
1.
What is exactly meant by "sandboxing around" libraries using exceptions, when my codebase runs with disabled exceptions and how does it work and how do I do that? (are there differences on platforms (Win/Linux/Mac, consoles or mobile?)
2. When using the standard library (which uses exceptions, as in new and the alikes) how I "sandbox" them - or is it the same principle as in 1.?

You can sandbox the exception by just caching it in a wrapper. Let's suppose you have:
a third party library T that DOES use exceptions
your application A that DOES NOT use exceptions.
You then create a wrapper W (compiled WITH exceptions enabled) that will wrap T but catch all exceptions wherever it exists and, for example, replace by and error code, like this:
// this one comes from the original library T that throws exceptions
void someFunctionInT();
// this will be your wrapper around the function above
int someFunctionInW()
{
try
{
someFunctionInT();
}
catch (...)
{
return -1;
}
return 0;
}
So, this way, your wrapper W should NOT throw any exception and you can use safely link against your application A.
Obviously, this is just a simple example. But you can do something a little "fancier" once at this time you already "paid" for the exception handling. For example, you can test the exception and return different error codes or prepare an error message to be retrieved from another function, etc, etc... up to your creativity. :-)

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.

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++

Throwing an exception in C++ in a C callback, possibly crossing over dynamic library boundary... is it safe?

I'm using libjpeg right now to save JPEG images. If there is an error, libjpeg's default behavior is to call exit(), which I want to avoid since it's not a fatal error for my program. libjpeg allows you to use your own error manager, and mandates that if you use your own error_exit() function (which calls exit() by default) you must not return control to the caller. libjpeg suggests using setjmp.h to meet this requirement and not exit() the program.
However, I am writing a C++ program, and I have access to exceptions. This question's answer states it's safe (as in well-defined behavior) to throw an exception from the callback. But it doesn't mention dynamic libraries, and there's a general rule of thumb that you don't throw exceptions across dynamic library boundaries.
Here's an example:
#include <iostream>
#include <jpeglib.h>
#include <cstdio>
#include <stdexcept>
static void handleLibJpegFatalError(j_common_ptr cinfo)
{
(*cinfo->err->output_message)(cinfo);
throw std::runtime_error("error in libjpeg, check stderr");
}
int main()
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE* file = std::fopen("out.jpeg", "wb"); // assume this doesn't fail for this example
try
{
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = handleLibJpegFatalError;
// let's say this triggers a fatal error in libjpeg and handleLibJpegFatalError() is called
// by libjpeg
jpeg_create_compress(&cinfo);
}
catch (...)
{
std::cerr << "Error saving the JPEG!\n";
}
jpeg_destroy_compress(&cinfo);
std::fclose(file);
}
What I would like to know is: can I throw an exception from this callback, and catch it back in my application, even if libjpeg is compiled as a dynamic library? libjpeg may be a static or dynamic library, and if it's a dynamic library it may possibly be built with a different compiler. However, the code that throws and catches the exception will certainly be in the same compilation unit. Is the above code safe?
FYI, I'm developing for OS X and Windows (and keeping the future of a Linux possibility in mind), so I'm more interested in if this is known to be well defined behavior in general, and not for a specific platform/compiler.
The other answer applies here. Nothing will get trashed when unwinding the stack. It doesn't even matter if the library uses some crazy calling convention internally, as long as it doesn't specifically mess with your C++ implementation's exception handling structures (which it wont as a C program). No C++ implementation that I know of finds the catch block by popping off stack frames (that would make optimization a nightmare), they all maintain internal structures for exception handling. As long as a call lower down in the call chain doesn't mess with those structures, stack unwinding will work perfectly fine for all of your personal code. Now, in general, it's quite possible that this would leave a library with a messed up internal state as you never return execution to the library for cleanup, but in the case of your error callback, libjpeg expects for control flow to not return and has presumably already cleaned up after itself.
In this case, I would go for it. In general, I would only throw fatal exceptions from a C callback.
Hope that helped.
It's not safe. Depending on how the relevant non-C++ library code was compiled, the necessary unwind tables may not exist. This is just a practical reason why it might fail; the conceptual reason is that it's simply undefined behavior.
You should follow the documentation and use setjmp/longjmp to get just outside the call to libjpeg code, then throw an exception immediately in the if (setjmp(...)) { ... } body if you want to use exceptions.
As discussed in other answers, it ought to be safe as long as you are in control of all the modules and they will be built by the same toolchain (inc. statically linking).
But I want to add a caveat here that some toolchains require this support to be turned on, since libjpeg's functions are marked extern "C". By default, Visual Studio assumes that such functions will not propagate exceptions.
If you don't turn this on, expect much pain. I spent hours on a testcase almost identical to yours before I realised this. 😃

Uncaught exception in a callback from a 3rd party static library

I am compiling my program with a 3rd party library. That library contains an error callback if an error occurs internally. Inside that error callback I am throwing an exception and I have a unit test to verify that when I do something invalid that the exception is thrown. This all works beautifully in Windows, but when I test this in linux (fedora) I am getting an abort from an uncaught exception.
I tried wrapping my call directly with a try-catch block but no luck. ( Also, all my code is running within the google test framework which also normally catches exceptions ). The only thing that seems to catch the exception is if I wrap the throw statement in a try block directly within the error callback.
Does anyone have any idea why this would happen and if there is a way to catch the exception?
When you interface with third-party libraries you usually have to catch all exception on the border between your code and their code:
int yourCallback( params )
{
try {
doStuff( params );
return Okay;
} catch (...) {
return Error;
}
}
The reason is you can't be sure that library is written in C++ or it uses the very same version of C++ runtime as your code uses.
Unless you're completely sure that code can deal with your exceptions you can't propagate exceptions to third-party code. The extreme example is COM where both your code and "other code" can be in whatever language and with whatever runtime and you are not allowed to let exceptions propagate through COM boundary.
Usually you should not throw exceptions "through" code you do not know anything about. It might be C code, which will not even clean up after itself.
How to deal with your concrete problem would require concrete information about the 3rd-party library you are interfacing with. What is that callback there for? To give you a chance to fix stuff? To inform you that an error occurred? Can you cancel whatever operation it is called from?
One way to deal with such a scenario is to store some information somewhere when the callback is called and check for that information when the actual processing finishes from your function that calls into that library.

Do c++ static libraries without mfc that are linked to an MFC project throw bad_alloc or CMemoryException*?

I'm working on a large, aging code base for an MFC app. The code has been worked on by many developers over time, and as a result, we have three different ways throughout the code of dealing with the possibility of an allocation failure with new.
The first way is to test for NULL on the result of new. We don't use nothrownew.obj so this is clearly an error that needs to be cleaned up.
The second is to catch CMemoryException* (yes, C++ exceptions are enabled in the compiler). From what I understand, MFC overrides the standard operator new, and throws this thing instead. I am fairly certain that this second method is correct in the MFC application itself. MFC overrides new, with its strange CMemoryException throwing version.
The last comes from our base of people who are good with C++, but aren't neccessarily MFC programmers. They are catching const std::bad_alloc&.
What I really don't know is what to expect for static libraries linked into the application. This is were the vast majority of the code that uses bad_alloc lives. Assuming these libraries are not compiled with MFC or ATL, and are written in standard C++ only, can they expect to catch bad_alloc? Or will the presence of MFC in the application they link to infect them with the global new operator and render their attempts to fail cleanly on a bad allocation moot?
If you have an answer, could you explain how this works, or point me to the right reference to sort this out?
It will depend on the compile options for the static libraries to be linked to the application.
If the libraries are compiled with a configuration to use the static Standard C++ run-time then I would expect the operator new from the Standard C++ run-time to be called.
If libraries are compiled with a configuration to use the Standard C++ run-time DLL then the resolution of these functions will be delayed until program load and should be resolved to the MFC replacements of operator new.
I also included a link to this Herb Sutter article regarding handle allocation errors that you may find useful.
Congratulations -- you seem to have stumped all of us. :-)
In theory, if MFC provides an overload for the global new function, then it should be used by all code in the program. But since the static libraries were compiled without knowing about that, I can't say for certain that it would.
The best I can suggest is to write some test code to find out. (I won't have access to my Windows system for the next few hours, or I'd do so myself and give you an answer.)
I've done some MFC-Code-Researches (in VC2010). Here are some facts.
The MFC throws a pointer to a global CMemoryException instance named "_simpleMemoryException" (see also AfxThrowMemoryException())
it is an CException whose m_bAutoDelete is false.
Idea: If it possible to change the c++-only-static-libraries, you can forward declare class CException; and/or class CMemoryException; into the root namespace.
Add a catch-block with catch (CMemoryException* pEx) {...} and/or catch (CException* pEx) {...} at each place where a std::bad_alloc-catch block is. Since the catched pointer is a pointer to a global object, it is not needed to call pEx->Delete();.
In this way the c++-only-static-libraries are not required to include afx.h or/and link against the MFC. I've tried it in VC2010, and it works fine. (only if RTTI is enabled, and only if nobody changes the MFC-NewHandler with AfxSetNewHandler to something else than the default-MFC-NewHandler AfxNewHandler)
You can change the MFC throwing behavior with AfxSetNewHandler(_PNH pfnNewHandler) and provide a pointer to your own NewHandler function. This function should then throw a std::bad_alloc exception.
But now the MFC-program-parts have the problem to catch a std::bad_alloc.