Tyson
Tyson

Reputation: 1238

std::set_terminate for DLL?

I have a DLL that will be loaded by another 3rd party application.

I'm trying to figure out if it's possible for me to catch any/all exceptions generated by my own DLL.

If I was in charge of the application's code, I'd use std::set_terminate within main() to set up a catch-all error handling function. But since my DLL will be inside someone else's application, I can't call std::set_terminate within main().

Is there a way for me to create such an override that just applies my own code, without doing something nasty like couching every single one of my application's functions inside a try/catch block or something?

Upvotes: 2

Views: 870

Answers (1)

Cody Gray
Cody Gray

Reputation: 244672

When designing a DLL, you should ensure that you never let exceptions escape from your entry points. Exceptions that cross module boundaries become tricky, if they work at all, and you are best off avoiding them.

Quoting from C++ Coding Standards: 101 Rules, Guidelines, and Best Practices by Herb Sutter and Andrei Alexandrescu:

Item 62: Don't allow exceptions to propagate across module boundaries.

Don't throw stones into your neighbor's garden: There is no ubiquitous binary standard for C++ exception handling. Don't allow exceptions to propagate between two pieces of code unless you control the compiler and compiler options used to build both sides; otherwise, the modules might not support compatible implementations for exception propagation. Typically, this boils down to: Don't let exceptions propagate across module/subsystem boundaries.

When you're dealing with a DLL, as opposed to a static library, you don't have any guarantees. The third-party application that consumes your DLL is a foreign module (the neighbor's garden). You have no guarantee that the two modules will be compiled with the same compiler and compiler options, so you don't know if they will treat exceptions the same way. In fact, you don't even know if both modules will be written in C++, so letting C++ exceptions propagate is right out. There are ways you can successfully propagate exceptions across module boundaries with Windows's Structured Exception Handling (SEH), but you shouldn't.

Aside from technical and implementation concerns, though, throwing exceptions from a DLL just creates a bad interface. The client application should not have to handle exceptions from your DLL's routines. Exceptions are implementation details: you should handle them internally. If you need to indicate success or failure, return an error code. Those can be trivially handled by any language that may consume your DLL, from C to BASIC to Python.

Your proposed solution is to basically hook up a global, unhandled exception handler that would catch any and all exceptions thrown by your DLL before they cross the module boundary. That doesn't really exist. DLLs don't have a global exception handler. Exceptions propagate by unwinding (walking up) the call stack until they find a suitable handler. If there's no handler, they'll propagate all the way up to the entry point (main), and if not handled there, they'll cause the application to terminate, and the operating system will present a "friendly" dialog. That's why it's easy to install an unhandled exception handler in the application. There's no such equivalent for a DLL, because the DLL doesn't have its own single, central main function. Instead, what it has is a series of entry points: exported functions that are called by the client application. So, your unhandled exception handlers should be in those entry points.

Each entry point would have its own exception handler. You can basically wrap the whole entry point in a big try-catch if you want. That way, all of your internal implementation functions can throw exceptions with reckless abandon, but they'll all be trapped in the entry points before they're allowed to propagate outside of the module.

Think of each entry point (exported function) provided by your DLL as its own main function, since that's basically what it is. The DllMain function (as it's conventionally known on Windows) is altogether different. You are so severely limited in terms of what you're allowed to do there that you should never be calling code that has the possibility of throwing an exception.

As an additional point, you probably don't want to be calling abort or std::terminate from code in a DLL anyway, since that will terminate the entire process, including the client application. When you're a guest in someone else's house, you shouldn't call the demolition company to have their house destroyed. Log your exception internally, but do whatever it takes to maintain a consistent external state and not crash the client application just because you experienced an internal error.

Upvotes: 6

Related Questions