17

I've got an unmanaged C++ dll which is being called from a C# app, I'm trying to get the C# app to catch all exceptions so that in the event of the dll failing due to an unmanaged exception then the user will get a half-decent error message (the C# app is a web service implementing it's own http handler).

The problem I have is that not all types are being caught. So if I create the following and execute the C# app then the dll throws an error and the entire application terminates. Any ideas?

This is being created in VS2005 and using .Net framework v2

C++ - Test.h

#ifndef INC_TEST_H
#define INC_TEST_H

extern "C" __declspec(dllexport) void ProcessBadCall();

#endif

C++ - Test.cpp

#include <iostream>
#include <vector>

using namespace std;

void ProcessBadCall()
{
  vector<int> myValues;
  int a = myValues[1];
  cout << a << endl;
}

C# - Program.cs

class Program
{
  [DllImport("Test.dll", EntryPoint="ProcessBadCall")]
  static extern void ProcessBadCall();

  static void Main(string[] args)
  {
    try
    {
      ProcessBadCall();
    }
    catch (SEHException ex)
    {
      Console.WriteLine("SEH Exception: {0}", ex.Message);
    }
    catch (Exception ex)
    {
      Console.WriteLine("Exception: {0}", ex.Message);
    }
  }
}

The dll is being compiled under the release configuration with the following compiler flags.

/O2 /GL /D "WIN32" /D "NDEBUG" /D "_CRT_SECURE_NO_WARNINGS" /D "_UNICODE" /D "UNICODE" /D "_WINDLL" /FD /EHa /MD /Fo"Release\" /Fd"Release\vc80.pdb" /W4 /WX /nologo /c /Wp64 /Zi /TP /errorReport:prompt

akjoshi
  • 15,374
  • 13
  • 103
  • 121
daz-fuller
  • 1,191
  • 1
  • 10
  • 18
  • when the dll is compiled in debug mode, this wont raise a SEH Exception, but will cause an assertation failure. – smerlin Nov 19 '10 at 09:19
  • Sorry, missed that bit out, the dll is compiled in release mode – daz-fuller Nov 19 '10 at 09:29
  • Have you tried "catch { Console.WriteLine("blah"); }"? – Polyfun Nov 19 '10 at 09:44
  • Just tried that, still no luck. What seems to be happening is that the DLL is throwing an unhandled exception which terminates both itself and the c# app immediately – daz-fuller Nov 19 '10 at 09:56
  • 2
    You should catch the exception in the same runtime that threw it. Else stack unrolling and destructor calls might not work as expected. And you typicall can't recover from a access violation, so you should terminate the application after displaying the error. – CodesInChaos Nov 19 '10 at 13:33
  • Thanks CodeInChaos, I'm thinking that there is not going to be a nice standard way of dealing with this. If you want to re-post your comment as an answer I'll flag it as accepted. Cheers – daz-fuller Nov 19 '10 at 13:48

1 Answers1

6

Try catching using the ExternalException class:

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.externalexception%28v=VS.100%29.aspx

And, try compiling your unmanaged C++ DLL with asynchronous exception handling (/EHa). It looks like you're getting a Read Access Violation in your DLL which is a type of async exception.

AFAIK, only .NET v4 and above disables the delivery of async exceptions by default. Even then, you could add legacyCorruptedState­­ExceptionsPolicy=true to the app.config to enable it. Prior to that, it's automatically enabled (check that you have got it set to false in app.config).

Note that it's my personal believe that AVs in your unmanaged DLL is inherently bad (and dangerous) anyway and it's probably the right behavior for .NET to simply terminate the app. Try throwing std::exception instead. If you insists on catching async exceptions, the best way would be to have a thunking DLL which wraps try-catch-all around the call to potentially buggy function calls. Again, highly /not/ recommended (although I can see how it would be useful in debugging the misbehaving DLL).

akjoshi
  • 15,374
  • 13
  • 103
  • 121
Zach Saw
  • 4,308
  • 3
  • 33
  • 49
  • Updated with comment on recompiling the DLL with /EHa compiler option. Please get that another go. – Zach Saw Nov 19 '10 at 11:33
  • Same again, I've added the compiler flags to the original question. Cheers – daz-fuller Nov 19 '10 at 11:47
  • Can you try throwing std::exception in your unmanaged DLL first? I'm wondering if .NET even repackages asynchronous exceptions from unmanaged code. – Zach Saw Nov 19 '10 at 12:36
  • 2
    If not, you could introduce an unmanaged DLL that thunks into the DLL that exports ProcessBadCall(). The thunking DLL would then wrap the call around try { } catch (...) { return errorCode; }. This way, only the thunking DLL would need to be compiled with /EHa. – Zach Saw Nov 19 '10 at 12:42
  • I've modified the demo app to throw a std::runtime_error before attempt to access uninitialized memory, this results in the C# app catching it and indicating that an SEHException type has been caught. – daz-fuller Nov 19 '10 at 13:27
  • I've also tried adding the "ProcessBadCall" into a try..catch block where I'm catching (...), the error escapes even this – daz-fuller Nov 19 '10 at 13:29
  • Try this: __try { AV_here(); } __except(EXCEPTION_CONTINUE_EXECUTION) { } – Zach Saw Nov 19 '10 at 13:31
  • Thanks Zach, I've just been looking at that and hoping that I can avoid it as it's a MS extension and I'm hoping to keep the code relatively platform independent, but if it's the only way then ... – daz-fuller Nov 19 '10 at 13:43
  • Catching async exceptions is vendor specific - e.g. in C++ Builder XE update 1, async exceptions are converted Delphi exceptions which can then be caught as per the usual System::Exception class. I would've thought the whole point of your question is really to facilitate debugging. A host and its plugins share the same process space - so it's normal for badly written plugins to take the host down with it. – Zach Saw Nov 24 '10 at 01:48
  • `legacyCorruptedState­­ExceptionsPolicy=true` - gold dust, when you really don't want an unmanaged DLL error to take out your whole C# application. – Baldrick Feb 26 '15 at 14:08
  • 2
    @Baldrick read [this article](https://msdn.microsoft.com/en-us/magazine/dd419661.aspx), there's an `[HandleProcessCorruptedStateExceptions]` attribute that lets you catch these exceptions in certain methods only, leaving the default .NET 4 behavior everywhere else. – Lucas Trzesniewski Mar 11 '15 at 16:06
  • How is this `asynchronous exception handling` flag called in gcc? – m4l490n Jan 12 '21 at 23:19