/clr and exceptions from native libs

R

rwf_20

I'm seeing incorrect (I think) behavior in the event of an exception
thrown in a native C++ library. Basically, the stack appears to
unwind correctly if the caller is native, but incorrectly if the
caller is /clr. Consider the following C++ static lib:

// ehTestLib.h
#include <iostream>
class worker {
public:
~worker() { std::cerr << "~worker()\n"; }
void doTheThingThatThrows();
};

class supervisor {
public:
~supervisor() { std::cerr << "~supervisor()\n"; }
void supervise();

private:
};

class director {
public:
~director() { std::cerr << "~director()\n"; }
void direct();
};

// ehTestLib.cpp
#include "ehTestLib.h"
void worker::doTheThingThatThrows() {
throw "";
}

void supervisor::supervise() {
worker w;
w.doTheThingThatThrows();
}

void director::direct() {
supervisor().supervise();
}

I build this lib via:
cl /c /EHsc /MD ehTestLib.cpp
link /out:ehTestLib.lib ehTestLib.obj


I test this library with the following code:
// ehTestApp.cpp
#include "ehTestLib.h"
int main() {
try {
director().direct();
}
catch (...) {
}
}

The expected output is, obviously:
~worker()
~supervisor()
~director()


Now, when I build ehTestApp.cpp as native C++:
cl /c /EHsc /MD ehTestApp.cpp
link /out:ehTestApp.exe ehTestLib.lib ehTestApp.obj

I get the expected output. However, when I build it as managed C++:
cl /c /clr /EHa /MD ehTestApp.cpp
link /out:ehTestApp.exe ehTestLib.lib ehTestApp.obj

I get the following only:
~director

Two other tidbits:
1. The problem as something to do with the throw being in a separate
library. If I simply include the code directly in the exe, everything
works as expected in native and /clr.
2. The native example works the same with /EHa or /EHsc.

I'm hoping someone out there has some insight as to why this is
happening. I've read through all of the related MSDN stuff (starting
with http://msdn2.microsoft.com/en-us/library/x057540h(VS.80).aspx),
but I don't see any mention of this.

Thanks in advance,
Ryan
 
R

rwf_20

Two other tidbits:
1. The problem as something to do with the throw being in a separate
library. If I simply include the code directly in the exe, everything
works as expected in native and /clr.
2. The native example works the same with /EHa or /EHsc.

Another thing I just discovered: this all works as expected with the
7.1 version of the compiler. The incorrect behavior I describe only
occurs in 8.0 (VS 2005).

Ryan
 
B

Ben Voigt [C++ MVP]

rwf_20 said:
I'm seeing incorrect (I think) behavior in the event of an exception
thrown in a native C++ library. Basically, the stack appears to
unwind correctly if the caller is native, but incorrectly if the
caller is /clr. Consider the following C++ static lib:

I see you compiled the host with both /EHsc and /EHa, but did you try the
library with /EHa?
 
R

rwf_20

I see you compiled the host with both /EHsc and /EHa, but did you try the
library with /EHa?

Never thought to try that, but it fixes the issue. Thanks for the
tip. I'm curious as to why it's now necessary to enable SEH in my
native libs? Something to do with the way the exceptions are handled
in the presence of the native/managed 'bridge'?

Are there any side-effects to using /EHa that I should know about?

Thanks again,
Ryan
 
B

Ben Voigt [C++ MVP]

rwf_20 said:
Never thought to try that, but it fixes the issue. Thanks for the
tip. I'm curious as to why it's now necessary to enable SEH in my
native libs? Something to do with the way the exceptions are handled
in the presence of the native/managed 'bridge'?

Because it forces the C++ compiler to use the OS exception support. The
..NET runtime only handles OS exceptions (SEH), so a /EHsc C++ exception
(which may be stored in an internal variable in the C++ runtime library)
won't be seen by the catch blocks, and hence the unwinding won't be done.

The stronger rule is to never throw exceptions across language boundaries,
because exceptions are language-specific (think MSIL for .NET, not
C#;VB.NET;F#;JavaScript.NET;C++/CLI;IronPython).

Possibly the C++/CLI compiler should catch both synchronous native C++
exceptions and SEH-based exceptions, but apparently it doesn't.
Are there any side-effects to using /EHa that I should know about?

Some optimizations aren't possible (removing try-blocks around functions
that can't throw, that sort of thing).

Also catch (...) clauses will catch non-C++ exceptions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top