views:

144

answers:

5

I've heard that throwing exceptions in/from a C++ library could be potentially dangerous, particularly with DLLs, and particularly if the calling code and the library are compiled with different compilers. Is there any truth to this? Is it safe as long as I stick to static libraries? Note that I am not talking about internal use of exceptions in the library only, I want to throw them deep into the calling code as well :)

Just to clarify: Say I got a compiled static library that defines class Foo like this:

class Foo
{
public:
    // Constructor
    Foo()
    {
        /* ... Do stuff ... */        
        if (stuffwentwrong)
            throw(123); // We throw an integer error code (to make it simple) 
    }
};

And some guy uses it like this:

try 
{
    Foo foo_object;
}
catch (int i)
{
    std::cout << "Oh bum. Code: " << i; 
}

Would that be safe?

A: 

I can't see any problem with this. It is perfectly acceptable to throw exceptions from DLLs.

Hades
FWIW that should come with a caveat. If you are an exported extern "C" function from a DLL then that implies that you shouldn't throw exceptions out. Ensuring that people who are calling your DLL know that you throw exceptions would be a good idea.
obelix
@obelix: You can not throw an exception across a function with C linkage (as it does not have the ABI to support exceptions). Your statement is a bit to broad as a DLL can expose both C and C++ points and if you stick with the default loader then it is all done seamlessly for you.
Martin York
I wouldn't say it's "perfectly acceptable" to throw exceptions from DLLs. As a general case it's a bad idea, see C++ Coding Standards #62: "Don't allow exceptions to propagate across module boundaries".However if you control the compiler and settings for both the DLL and the other module calling it, and you're certain this is never going to change, then yes you can do it, carefully.
Brook Miles
+1  A: 

and particularly if the calling code and the library are compiled with different compilers

You generally can't mix different C++ compilers that do not have compatible ABI. So, for example, you can't throw exception from library compiled with MSVC and try to catch it with GCC.

But otherwise, you generally have no issues.

Small note:

MSVC has several incompatible exception models, don't mix them.

Artyom
there are a lot of other subtleties that make it dangerous in general though. For example if the DLL is compiled with a different version of the CRT you will be screwed (e.g. debug vs. release, or multithreaded vs. single threaded). Also the CRT stores certain state at the module level, not the process level (for example hModule, or memory tracking information), so when you transmit CRT-dependent objects across DLL boundaries all of these things can get out of sync. And the errors are at run-time, and can be very subtle / head-scratchers. In general avoid this.
tenfour
A: 

Your example you gave should work fine, however with DLLs, if you happen to throw a heap allocated exception, you will crash if the consumer of the DLL attempts to free the heap allocated exception.

carribus
+1  A: 

With respect to GCC, there is at least one case where catching exceptions from GCC generated shared libraries can be problematic, i.e. when forgetting to export the throwable type from the shared library when symbol visibility is "hidden" by default. The GCC Visibility Wiki page goes into good detail about the issue, and how to prevent it.

I'm not sure if Windows DLLs have similar issues, but it seems likely.

Void
A: 

General gotcha when it comes to DLLs and exceptions:

Don't implement the exceptions class inline in the header. You will end up with duplicate vtables and RTTI information, resulting in exceptions not being caught in the using code (due to the duplication, the exception is considered to be of another type).

The details:

http://marcmutz.wordpress.com/2010/08/04/fun-with-exceptions/

Frank