Exceptions raised running COM DLL - c#

I will try again .... :)
If I have this code:
void CTestDlg::OnBnClickedButtonTest()
{
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
HRESULT hr;
hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (FAILED(hr))
{
__int64 i;
p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
p->ReadPublisherData(&i);
}
}
And I run it, I get this silent exception:
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000099D88FBDC0).
But, if I use a wrapper (header:
#pragma once
#import "D:\\My Programs\\2017\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\Release\\MSAToolsLibrary.tlb" raw_interfaces_only named_guids
class CMSATools
{
public:
CMSATools();
~CMSATools();
void SetPathXML(CString strPath);
void OpenPublisherDatabase();
private:
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr m_pInterface;
}
Class:
#include "stdafx.h"
#include "MSATools.h"
CMSATools::CMSATools()
{
m_pInterface = NULL;
HRESULT hr;
hr = m_pInterface.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (FAILED(hr))
{
// TODO: Throw exception ?
}
}
CMSATools::~CMSATools()
{
}
void CMSATools::SetPathXML(CString strPath)
{
if (m_pInterface != NULL)
{
CComBSTR bstrText = strPath.AllocSysString();
__int64 iResult;
m_pInterface->SetPathXML(bstrText, &iResult);
}
}
void CMSATools::OpenPublisherDatabase()
{
__int64 iResult;
if (m_pInterface != NULL)
m_pInterface->ReadPublisherData(&iResult);
}
And use this in MFC instead:
void CTestDlg::OnBnClickedButtonGetNames()
{
CMSATools toolsMSA;
UpdateData(TRUE);
toolsMSA.SetPathXML(m_strPublisherDatabaseXML);
toolsMSA.OpenPublisherDatabase();
}
It is doing the same thing, yet I get these silent exceptions:
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000090F277C040).
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0xE0434352 (parameters: 0xFFFFFFFF80070002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00007FFCBF6C0000).
Why should one way work and the other cause exceptions (that I can't seem to even detect)?
UPDATE
Please hold off - I see my stupid error now! One moment ....
UPDATE 2
void CTestDlg::OnBnClickedButtonTest()
{
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
HRESULT hr;
hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (SUCCEEDED(hr))
{
__int64 i;
p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
p->ReadPublisherData(&i);
}
}
I corrected the test case now and they both have the same exceptions raised. This is the method that seems to cause the problem in the DLL:
public void ReadPublisherData(out Int64 iResult)
{
iResult = MakeResult(true);
try
{
_PublisherData.Publishers.Clear(); // Reset
XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
using (StreamReader reader = new StreamReader(_strPathXML))
{
_PublisherData = (PublisherData)x.Deserialize(reader);
_PublisherData.BuildPublisherDictionaryFromList();
iResult = _PublisherData.PublisherDictionary.Count;
}
}
catch
{
iResult = MakeResult(false);
}
}
As far as I am aware it doesn't cause any exceptions. It seems ...

The only obvious problem you have is that you don't have a problem. The COM server you are using was written in a managed language. Pretty common, dead-simple to do with just an attribute. Probably C#, given that you've asked questions about it. The point is that these exceptions are silent, they are thrown and caught inside the managed code.
Passing exceptions across a COM boundary is illegal, the CLR gives you a rock-hard guarantee that this will never happen. If a managed exception is not caught then it gets turned into an HRESULT error code that indicates a failure. Since you are using the wrappers generated by #import, you'll never actually see these error codes, the wrapper turns them back into a C++ exception by throwing a _com_error. You make no attempt at catching them so if it happens then your program will keel over and die on terminate(), impossible to not notice that.
Fwiw, 0x04242420 is a non-fatal exception code and is an implementation detail of the debugger. Documented here.
The EEFileLoadException is an unmanaged exception used inside the CLR and triggered when Fusion is asked to load assembly and it can't find it. Turns into a managed FileLoadException. You might be slightly more concerned about it given that managed COM servers often have a problem finding dependent assemblies. But this commonly happens when the managed code uses XML serialization, we know you are using it. Using exceptions for flow-control isn't very nice but performance is a feature as well. More about it in this post.
So rather best to not fret about it. If you don't trust your COM server to be implemented correctly then simply debug both. Project > Properties > Debugging and change the Debugger Type setting from Auto to Mixed. And use Debug > Windows > Exception Settings and tick the checkbox for CLR Exceptions to force the debugger to break when a managed exception is thrown.

Related

How can I resolve an access violation in managed C# code with structs?

Problem: When I attempt to access a derived property of a C# struct, it results in an access violation error and the application exits abruptly (with status 0xC0000005). Unlike this question, it happens deterministically on a single property.
The struct definition is in a different library however I control both the client application and the library where the struct is defined.
There is no unmanaged code that I've written for this project. I'm using .NET 5 in both the client application and the library.
Things I've Tried:
Changing the output to x64 in the library didn't help (the application output is x64)
Enabling native code debugging (no information was provided)
MCVE:
Definition
public struct Foo
{
public const Double BarDivisor = 100.0;
// ...other properties...
public Int64 BarWholePart { get; }
public Int64 BarFractionalPart { get; }
public Double Bar => Bar + (BarFractionalPart / BarDivisor);
public Foo(Int64 wholePart, Int64 fractionalPart, /* ... */)
{
// ...
BarWholePart = wholePart;
BarFractionalPart = fractionalPart;
}
public static Foo Parse(Int64 whole, Int64 fractional)
{
return new Foo(whole, fractional);
// ...
}
}
Example of calling code
public void Baz(Foo bar)
{
// ...
Double foobar = bar.Bar; // this line results in a crash of the application
// ...
}
Exception Messages:
Exception thrown at 0x00007FF8C85A21A0 (coreclr.dll) in [application name removed]: 0xC0000005: Access violation writing location 0x000000E70B180FF8.
The Common Language Runtime cannot stop at this exception. Common causes include: incorrect COM interop marshalling and memory corruption. To investigate further use native-only debugging.
Unhandled exception at 0x00007FF8C85A21A0 (coreclr.dll) in [application name removed]: 0xC0000005: Access violation writing location 0x000000E70B180FF8.
The Common Language Runtime cannot stop at this exception. Common causes include: incorrect COM interop marshalling and memory corruption. To investigate further use native-only debugging.
This is caused because of a typographical error here
public Double Bar => Bar + (BarFractionalPart / BarDivisor);
BarWholePart should be used instead of Bar. This causes a StackOverflowException, but can sometimes cause an AccessViolationException in the debugger.

Exception on exit() when using C# event source with c++ sink

I have a COM object, implemented in a C# .dll, named ComClass which sources events. Then, I have a C++ object, SimpleSink, that sinks the events sent from ComClass. The event source/sink mechanism works great. But, when the CRT calls exit(), I'm getting a memory access exception thrown from the following code in exe_common.inl
//
// main has returned; exit somehow...
//
if (!__scrt_is_managed_app())
exit(main_result); // Exception is thrown.
The text of the exception message is as follows.
Exception thrown at 0x00000004 in Cpp.exe: 0xC0000005: Access violation executing location 0x00000004.
I understand that something is attempting to access a junk memory location, but I'm unsure as to what. I researched the issue and I came across this, from Microsoft.
https://msdn.microsoft.com/en-us/library/ms235234.aspx
Once the common language runtime (CLR) enters shutdown mode, native functions have limited access to CLR services. When attempting to call Release on a COM object compiled with /clr, the CLR transitions to native code and then transitions back into managed code to service the IUnknown::Release call (which is defined in managed code). The CLR prevents the call back into managed code since it is in shutdown mode.
I'm not sure if this is applicable only to C++ /clr compiled COM objects, or all CLR compiled COM objects. It may be a cold lead, so to speak. I understand that I could disable the exception and 'probably' go about my business, but that makes me feel oily. So, the question is, how can I prevent this exception when my program shuts down?
Here it is.
int main()
{
CoInitialize(NULL);
// explicit scope so that the smart pointer destructs at the correct time
{
IComClassPtr source;
HRESULT createInstance = source.CreateInstance(__uuidof(ComClass));
SinkSimple sink;
HRESULT advise = sink.DispEventAdvise(source);
try
{
source->FireEvent();
}
catch (const _com_error& ex)
{
std::cout << "Error: " << ex.Description();
}
HRESULT unadvise = sink.DispEventUnadvise(source);
}
CoUninitialize();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}

Can an .Net exception be raised from unmanaged code using a delegate function?

I searched around SO and found various related questions, some answered with essentially "don't do that."
I want to call some unmanaged C++ code that accesses various existing C++ code. The existing code may have a variety of error conditions that I want to map into C# exceptions. From doing something similar in Java and JNI, it seemed that it might be possible to have a delegate function to raise defined exceptions, which could then be called directly from unmanaged code. The calls then look like (csharp)->(unmanaged)->(csharp delegate,throw/set pending exception) and then return back up.
The code below seems to work fine (vs2010, mono). My question is is there any problem with this approach - e.g. the spec says that the exception is not guaranteed to still be "pending" after unmanaged code is called, or threading issues, etc...
// unmanaged.cpp
#include <cstdio>
#define EXPORT __declspec(dllexport)
#define STDCALL __stdcall
typedef void (STDCALL* raiseExcpFn_t)(const char *);
extern "C" {
// STRUCT ADDED TO TEST CLEANUP
struct Allocated {
int x;
Allocated(int a): x(a) {}
~Allocated() {
printf("--- Deleted allocated stack '%d' ---\n", x);
fflush(stdout);
}
};
static raiseExcpFn_t exceptionRaiser = 0;
EXPORT void STDCALL registerRaiseExcpFn(raiseExcpFn_t fun) {
exceptionRaiser = fun;
}
EXPORT void STDCALL hello(const char * x) {
Allocated a0(0);
try {
Allocated a1(1);
printf("1 --- '%s' ---\n", x); fflush(stdout);
(*exceptionRaiser)("Something bad happened!");
printf("2 --- '%s' ---\n", x); fflush(stdout);
} catch (...) {
printf("3 --- '%s' ---\n", x); fflush(stdout);
throw;
}
printf("4 --- '%s' ---\n", x); fflush(stdout);
}
}
// Program.cs
using System;
using System.Runtime.InteropServices;
class Program {
[DllImport("unmanaged.dll")]
public static extern void registerRaiseExcpFn(RaiseException method);
[DllImport("unmanaged.dll")]
public static extern void hello([MarshalAs(UnmanagedType.LPStr)] string m);
public delegate void RaiseException(string s);
public static RaiseException excpfnDelegate =
new RaiseException(RaiseExceptionMessage);
// Static constructor (initializer)
static Program() {
registerRaiseExcpFn(excpfnDelegate);
}
static void RaiseExceptionMessage(String msg) {
throw new ApplicationException(msg);
}
public static void Main(string[] args) {
try {
hello("Hello World!");
} catch (Exception e) {
Console.WriteLine("Exception: " + e.GetType() + ":" + e.Message);
}
}
}
Updated: Corrected test and output, showing mono and Windows (with /EHsc) leaks
// Observed output // with Release builds /EHa, VS2010, .Net 3.5 target
//cstest.exe
// --- Deleted allocated stack '0' ---
// --- Deleted allocated stack '1' ---
// 1 --- 'Hello World!' ---
// 3 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// Observed LEAKING output // with Release builds /EHsc, VS2010, .Net 3.5 target
// cstest.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// LEAKING output DYLD_LIBRARY_PATH=`pwd` mono program.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
Yes, you can make this work as long as you run the code on Windows. Both C++ exceptions and .NET exceptions are built on top of the native SEH support provided by Windows. You will not have such guarantee on Linux or Apple operating systems however, a concern when you use Mono.
It is important that you build your C++ code with the correct settings, the MSVC++ compiler uses an optimization to avoid registering exception filters when it can see that code can never throw a C++ exception. That cannot work in your case, your RaiseException delegate target is going to throw one and the compiler has no chance at guessing at that. You must compile with /EHa to ensure your C++ destructors will be called when the stack is unwound. You'll find more details in this answer.
If you're ever planning on running on Mono, the answer is simple:
Don't do it
No more code will be executed in the native methods the exception would unwind over. No cleanup, no C++ destructors, nothing.
On the other hand this means that if you're sure none of the native frames on the stack have any cleanup to do (if you're writing C++ code this can be harder than it looks), then you're free to throw managed exceptions at will.
The reason I so adamantly advice against doing this is because I once spent two days tracking down a memory leak because of exception handling unwinding though native frames. It is quite hard to track down and I was quite boggled for a while (breakpoints aren't hit, printfs don't print... but with the right tools it could have taken 5 minutes).
If you're still decided on throwing managed exceptions from native code, I'd do it just before returning to managed code:
void native_function_called_by_managed_code ()
{
bool result;
/* your code */
if (!result)
throw_managed_exception ();
}
And I would limit myself to C in those methods, since it's too easy to get into automatic memory management in C++ that would still leak:
void native_function_called_by_managed_code ()
{
bool result;
MyCustomObject obj;
/* your code */
if (!result)
throw_managed_exception ();
}
This could leak because MyCustomObject's destructor isn't called.
You might have a problem with native resources not being freed correctly.
When an exception is thrown the stack gets unwind until it finds a matching try-catch block.
This is all good and nice, but there are some side effects of being in the middle of native and managed.
In regular C# all the objects created in the blocks on the way to the exception would eventually be freed by the garbage collector. But Dispose() isn't called unless you're in a using block.
On the other hand, in C++ if you'd have a native exception, all object created with new() would probably stay dangling and you'll have a memory leak, and the objects on the stack would be destroyed properly when the stack got unwound.
BUT if you don't have /EHa set, and you have a managed exception, it will only unwind the managed code. So, the native destructors of native objects created on the stack might not be called, and you might have memory leaks, or even worse - locks not being unlocked...

How to find exceptions thrown by OpenReadAsync method

Consider the following code:
using (IRandomAccessStream stream = await storageFile.OpenReadAsync())
{
using (DataReader dataReader = new DataReader(stream))
{
uint length = (uint)stream.Size;
await dataReader.LoadAsync(length);
txtbox.Text = dataReader.ReadString(length);
}
}
storageFile.OpenReadAsync may throw exception, System.IO.FileNotFoundException is one possible exception type. MSDN topic StorageFile.OpenReadAsync http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.storagefile.openreadasync doesn't contain list of exception types thrown by this method. How can I find this information from documentation? I can catch an Exception type, but this is poor programming practice.
In cases where it is impossible to find all list of exceptions I usually use approach from VS SDK ErrorHandler.IsCriticalException:
try
{
// ...
}
catch(Exception e)
{
if (ErrorHandler.IsCriticalException(e))
{
throw;
}
// log it or show something to user
}
You can decompile the Microsoft.VisualStudio.Shell.11.0.dll to find the list of exceptions, which ErrorHandler defines as Critical:
StackOverflowException
AccessViolationException
AppDomainUnloadedException
BadImageFormatException
DivideByZeroException
In the case of Windows Runtime I think that it will be good also to verify some of the HResult values in Exception, like E_OUTOFMEMORY, E_ABORT, E_FAIL, and maybe something else.
Also I found that BugSense is awesome help for logging exceptions. I use it not only for unhandled exception, but also for situations like this, where I have no idea what this method can throw. It allows to send custom logging (including exceptions) with BugSenseHandler.Instance.LogException, so I just collect information about different kind of exceptions (including exceptions with some unexpected HResult) and make some improvements for my app in each release.

Unhandled Exception in C# Console Application causing AppCrash

I have a Windows Console application built in Visual Studio 2010 and it keeps crashing but the error is not caught by the visual studio debugging tool nor by try/catch statements in my code.
I have managed to locate the WER file on my system and would like to be able to understand the contents of the file so I can pinpoint exactally what is causing the unhandled exception.
I would be greatful if anyone can offer some idea on how I can use the following information to locate the process causing me this problem and also what the exception may be...
The information from the WER file is:
Version=1
EventType=APPCRASH
EventTime=129973086237604286
ReportType=2
Consent=1
ReportIdentifier=91331e8b-2dc8-11e2-977b-080027f7e5bb
IntegratorReportIdentifier=91331e8a-2dc8-11e2-977b-080027f7e5bb
WOW64=1
Response.type=4
Sig[0].Name=Application Name
Sig[0].Value=SAGE_TESTING.vshost.exe
Sig[1].Name=Application Version
Sig[1].Value=10.0.30319.1
Sig[2].Name=Application Timestamp
Sig[2].Value=4ba2084b
Sig[3].Name=Fault Module Name
Sig[3].Value=ntdll.dll
Sig[4].Name=Fault Module Version
Sig[4].Value=6.1.7600.16385
Sig[5].Name=Fault Module Timestamp
Sig[5].Value=4a5bdb3b
Sig[6].Name=Exception Code
Sig[6].Value=c015000f
Sig[7].Name=Exception Offset
Sig[7].Value=000845bb
DynamicSig[1].Name=OS Version
DynamicSig[1].Value=6.1.7600.2.0.0.272.7
DynamicSig[2].Name=Locale ID
DynamicSig[2].Value=2057
DynamicSig[22].Name=Additional Information 1
DynamicSig[22].Value=0a9e
DynamicSig[23].Name=Additional Information 2
DynamicSig[23].Value=0a9e372d3b4ad19135b953a78882e789
DynamicSig[24].Name=Additional Information 3
DynamicSig[24].Value=0a9e
DynamicSig[25].Name=Additional Information 4
DynamicSig[25].Value=0a9e372d3b4ad19135b953a78882e789
Here is the section of code I believe to be causing the exception to be thrown:
//Data from the project linked to the split data
if (oSplitData.Project != null)
{
oProject = oSplitData.Project as SageDataObject190.Project;
oBasicDetail.ProjectID = oProject.ProjectID;
oBasicDetail.ProjectReference = oProject.Reference.ToString();
}
else
{
oBasicDetail.ProjectID = -1;
oBasicDetail.ProjectReference = "NO_PROJECT";
}
To add to all the above I seem to have found that there is a general exception that is being thrown but it doesn't help me out much - if anyone can put some light on this it would be great:
Unhandled exception at 0x78bc7361 in SAGE_TESTING.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
If your program is multi-threaded and the exception is thrown in one of the spawned threads, the Exception may not be caught depending on how you do exception handling in your program.
You can add a catch-all exception handler like this:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
// Your code here
}
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
Environment.Exit(1);
}
}
UPDATE
Based on the code you posted, here are some things to look at
Put a try/catch block around the code you posted.
Are you sure that oSplitData is not null?
In the following line, oProject will be null if oSplitData.Project is not of type SageDataObject190.Project. Test for null.
oProject = oSplitData.Project as SageDataObject190.Project;
You are probably dealing with so-called corrupted state exceptions. These exceptions corrupt the process in a way so it is usually more safe to kill the process since it is very difficult to impossible to recover from such an error, even if it would be only for running a short catch-clause. Examples are StackOverflowExceptions, OutOfMemoryExceptions or AccessViolationExceptions.
There is an extensive and generally interesting explanation on corrupted state exceptions in this article.
What is helpful on getting a hand on such exceptions is to use DebugDiag. With this tool from Microsoft (download on this page) you can define a crash rule which generates a crashdump for your failed process. You can easily open these dump files in Visual Studio, where you may find the source of the exception that lead to the failure. This is not guaranteed but it often helped me in the past to nail down some nasty errors.
Are you invoking non-managed C++ or other code?
I'd try something like
static void Main()
{
try
{
DoSomethingUseful() ;
}
catch ( Exception e )
{
// managed exceptions caught here
}
catch
{
// non-managed C++ or other code can throw non-exception objects
// they are caught here.
}
return ;
}
See Will CLR handle both CLS-Complaint and non-CLS complaint exceptions?
Also C++ try, catch and throw statements at msdn: http://msdn.microsoft.com/en-us/library/6dekhbbc(v=vs.100).aspx
And MSIL opcode throw (0x7A) allows the throwing any object reference. C#, however, does not allow it.
But it looks like they improved things with .Net 2.0 and started wrapping oddball stuff in an RuntimeWrappedException.

Categories

Resources