Thomas Nguyen
Thomas Nguyen

Reputation: 494

Exceptions propagating from unmanaged code to managed code?

I have a chunk of unmanaged C++ code I am reusing on a C# project. The unmanaged C++ code is wrapped inside a layer of managed C++ code, which interacts with the C# code. Right now, the unmanaged C++ code uses assert(false) to raise critical errors. Since assert() writes to stderr and my project is a GUI program I don't think the assert printouts will show up. I'm thinking of replacing the assert(false) with throw new exception(...) and then catch and display the exceptions at the C# GUI layer. My questions are:

1) Is replacing assert() with exception() a good idea? if not why?

2) If exceptions are thrown inside unmanaged C++ code, will they propagate properly to the managed C++ and then to C# code (with the stack trace intact and correct)?

Thanks,

Upvotes: 2

Views: 2515

Answers (1)

IInspectable
IInspectable

Reputation: 51420

1) Is replacing assert() with exception() a good idea? if not why?

assert is a debugging tool. It will evaluate to a no-op in a release build and is not meant to be used as an error handling facility. Implementing an error reporting system based on exceptions is the natural thing to do in C++.

2) If exceptions are thrown inside unmanaged C++ code, will they propagate properly to the managed C++ and then to C# code (with the stack trace intact and correct)?

C++ exceptions thrown in native code will be converted to SEHExceptions when tavelling from unmanaged to managed code. C++ exceptions can be handled in native code, in a C++/CLI interop layer or in managed code. (Human readable) call stack information is not available in native code.


Background information on exception handling in a mixed mode environment:

C++ exceptions (as implement in Microsoft's C++ compiler) as well as exceptions in the CLR are built on top of SEH Exceptions. Structured Exception Handling is a service built into Windows that can be consumed by any environment that can interface with C. Sharing the same foundation enables exceptions to seamlessly propagate from managed to unmanaged code and vice versa.

All SEH exceptions carry the same information stored in an EXCEPTION_RECORD. The ExceptionAddress member is used as the entry point in constructing a stack trace. Managed assemblies contain enough meta data to construct a human readable stack trace. Native executable images on the other hand do not. While it is possible to produce a stack trace (using StackWalk64, for example) no symbolic information will be included unless the respective debugging information (.pdb) is available.


Alternatives to a stack trace:

While a stack trace may give you a few hints where an exception was raised it does not contain any more helpful information for debugging, such as parameters and locals. An alternative would be to write a minidump instead. MiniDumpWriteDump is an immensely powerful tool to do so, giving you very fine grained control over which data should be included. A very good introduction can be found at Effective Minidumps - Part 1 and Effective Minidumps - Part 2. Minidumps can be loaded into a debugger (such as Visual Studio or WinDBG) and analyzed. With matching debugging symbols (which you should add to your source control system for any release) you get an insanely effective infrastructure for analyzing problems. Depending on the minidump information available you will get the call stacks for all threads, parameters passed to functions, contents of locals, loaded and unloaded modules, etc.

Upvotes: 5

Related Questions