8

I know this is frowned upon, but I'm out of options here. I'm developing a C++/CLI app that has a bug that I'm unable to track down - mainly because it's bypassing my current crash handler:

AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&LogAndExit); Application::ThreadException += gcnew ThreadExceptionEventHandler(&LogAndExit); Application::SetUnhandledExceptionMode(UnhandledExceptionMode::CatchException); try { Application::Run(gcnew frmMain()); } catch (Exception^ ex) { LogAndExit(ex); } catch (...) { LogAndExit(); } 

Standard .NET crash handling, I suppose. MSDN reports that some of the CRT exceptions will blow over the managed stack and silently abort the app.

I've been reading up on _set_invalid_parameter_handler, but even though I'm getting a LNK2001 error, it seems it can't be used with /clr:pure. Am I right, or am I just PEBKACing it up and missing a lib file?

4
  • 1
    Debug + Exceptions, tick the Thrown flags. Commented Aug 11, 2011 at 19:38
  • Can't. Don't have VS2010 installed on the target machines. Commented Aug 11, 2011 at 21:35
  • Would it not be possible to have the JIT dumper built in to windows grab a dump for you? Commented Aug 18, 2011 at 18:44
  • I'm actually writing a full memory dump whenever I can catch the exception - but that's not always the case. :/ Commented Aug 23, 2011 at 17:22

5 Answers 5

4

Can you run in /clr mode? If you can then try this:

#include <exception> 

Then:

try { try { Application::Run(gcnew frmMain()); } catch(const exception& ex) { throw gcnew System::Exception(gcnew System::String(ex.what())); } } catch (Exception^ ex) { LogAndExit(ex); } catch (...) { LogAndExit(); } 

Another thing to note: if your application is multi-threaded, then you will only catch an exception from the thread in which frmMain() is running. So doing a catch-all on your entire application is impossible in that case!

Sign up to request clarification or add additional context in comments.

5 Comments

I used to run in /clr, but one of my machines (ATM machines) didn't work. /clr:pure worked with all of them.
@hb, ok, well the other question is still valid: are you running multiple threads?
The C++/CLI process hosts a net.pipe WCF service, so I guess that's a yes. All of the methods are try/catch'd though (CLR)
@hb, and they're all logging the exceptions I assume? If they are, then you might might just have to track down the failure... of course, you already knew that...
Hah... yeah, precisely. Nothing gets shown, but sometimes it just dies.
1

First of all, this doesn't work for forms.

In applications that use Windows Forms, unhandled exceptions in the main application thread cause the Application.ThreadException event to be raised. If this event is handled, the default behavior is that the unhandled exception does not terminate the application, although the application is left in an unknown state. In that case, the UnhandledException event is not raised. This behavior can be changed by using the application configuration file, or by using the Application.SetUnhandledExceptionMode method to change the mode to UnhandledExceptionMode.ThrowException before the ThreadException event handler is hooked up. This applies only to the main application thread. The UnhandledException event is raised for unhandled exceptions thrown in other threads.

Second, there might be an unmanaged exception (which is not of type System::Exception).

try { Application::Run(gcnew frmMain()); } catch (Exception^ ex) { LogAndExit(ex); } catch (...) { LogAndExit(new Exception("Some Unmanage exception")); 

msdn- How to catch exceptions in Visual C++

3 Comments

Er, yeah. I forgot to copy that. Actual code in question now.
Did you read the MSDN article about how forms are affected with CurrentDomain->UnhandledException ?
Yeah. Thing is none of those handlers are being used and just defaults to the default Windows "This app just crashed" dialog
1

I recommend you try a __try / __except

__try { Application::Run(gcnew frmMain()); } __except(EXCEPTION_EXECUTE_HANDLER) { LogAndExit(new Exception("Some Unmanage exception")); } 

MSDN documentation here:

http://msdn.microsoft.com/en-us/library/s58ftw19(v=vs.80).aspx

If you wanted to get really tricky, you could try double wrapping it like this:

__try { try { Application::Run(gcnew frmMain()); } catch(SEHException^ e) { LogAndExit(new Exception("Some Unmanage exception")); } catch(...) //Leave this out if you're /clr:pure { LogAndExit(new Exception("Some Unmanage exception")); } } __except(EXCEPTION_EXECUTE_HANDLER) { LogAndExit(new Exception("Some Unmanage exception")); } 

Structured exceptions are wrapped into SEHException^ generally.

You also need to take into account that you may in fact be catching the exception, but that something in your LogAndExit method is causing a secondary exception to be thrown which is actually what is ending your program. Try stubbing out your LogAndExit function and see if you can make the crash happen silently rather than with a standard abort message and/or wrap your LogAndExit code in another try/catch that hides any exceptions.

As someone who has put significant time into C++/CLI, I can sympathize with your dilemma. Hope this solution helps.

Additional MSDN documentation on C++/CLI exception handling:

How to: Define and Install a Global Exception Handler http://msdn.microsoft.com/en-us/library/171ezxzc.aspx

Exception Handling under /clr http://msdn.microsoft.com/en-us/library/633chdda.aspx

1 Comment

I'm using full dumps in the __except handler to try and figure out what the hell is going on. Anything else you can recommend? If I hadn't lost my hair already, I would've probably ripped it out by now.
0

There are several types of exception handling. What you posted will only handle managed exceptions.

It's also possible for C++ code to throw unmanaged exceptions (particularly from the standard library). Furthermore, it's possible for unmanaged code to throw a Win32 exception.

Start here and read up on structured exception handling (Win32 exceptions). C++ exceptions and managed exceptions are built on SEH, so if you handle SEH at the top point of every thread in your process, you'll be covered.

12 Comments

Does that post also apply to /clr:pure?
I believe you're correct; clr:pure only supports managed code.
Managed exceptions use SEH, and managed handlers handle SEH exceptions. If C++ code is using /EHa, any exceptions it throws will use SEH underneath as well. There's no way for managed code to catch native C++ exceptions compiled with the synchronous model (/EHsc).
So, if I'm having a C++ exception, I'm SOL w/ depending on a stack trace to see where it's coming from?
I believe that it's not possible to get a C++ (or Win32) exception in clr:pure mode. Almost positive... At this point, your best bet is to get a minidump (e.g., via ProcDump) and load it into WinDbg or Visual Studio.
|
0

Not every crash is an exception, at least not immediately. It's entirely possible for a wild pointer to stomp on .NET internal data structures so badly that when an exception is thrown, the managed handler can't run correctly.

Try using a native handler instead. Visual C++ provides __try/__except, but you'll need to make sure the handler is on the call stack of every thread in your program, and it's still possible for an exception to go unhandled (e.g. CreateThread with a pointer to an illegal instruction). To deal with all edge cases, you should instead use SetUnhandledExceptionFilter.

Note that with /clr:pure, all code is dependent on the CLR, and so subject to failure due to runtime corruption. Even native handlers might depend on corrupted state, although they're less fragile that MSIL-based handlers. For robust error-handling, you really need code running outside the process.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.