I have a simple function inside of a click handler that has a try catch block. If I throw an exception within this try catch block it catches the exception successfully.
If I put a call to an unmanaged DLL before I throw the exception the exception is unhandled and not caught.
What is the unamanged DLL call doing that could be breaking my programs exception handling?
If I run the program in debug mode it catches the exception even with "break on exception" unticked for all exceptions. The application does not crash and runs as expected.
If I run the program as "start without debugging" and hit debug when it crashes I get the following error "Stack cookie instrumentation code detected a stack-based buffer overrun"
edit:
It appears the stack overflow breaks the exception handling
I've attached a simplified program that produces the crash.
ISOConnection _comm; //This is instantiated at another time in the same thread
//C# test function that crashes when run without a debugger attached
bool DoMagic()
{
try
{
//if I uncomment this line the exception becomes unhandled and cannot be caught
//_comm.ConnectISO15765();
throw new Exception();
}
catch (Exception ex)
{
MessageBox.Show("Caught exception")
}
//Within ISOConnection class
public void ConnectISO15765(){
...
lock(syncLock){
uint returnCode = J2534Interface.PassThruConnect((uint)DeviceId, (uint)ProtocolID.ISO15765, (uint)ConnectFlag.NONE, (uint)BaudRate.ISO15765, ref ChannelId);
//C# UnmanagedFunctionPointer allocation code
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId);
public PassThruConnect Connect;
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
m_pDll = NativeMethods.LoadLibrary(path);
...
pAddressOfFunctionToCall = NativeMethods.GetProcAddress(m_pDll, "PassThruConnect");
if (pAddressOfFunctionToCall != IntPtr.Zero)
Connect = (PassThruConnect)Marshal.GetDelegateForFunctionPointer(
pAddressOfFunctionToCall,
typeof(PassThruConnect));
//C++ function declaration
long PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long Baudrate, unsigned long *pChannelID);
UPDATE
If I replace the call to the UnmanagedFunctionPointer PassThurConnect with the following the crash does NOT occur
[DllImport("op20pt32.dll", EntryPoint = "PassThruConnect", CallingConvention = CallingConvention.Cdecl)]
public static extern uint PassThruConnect2(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId);
Is there something I am not performing or I am performing incorrectly when assigning the UnmanagedFunctionPointer that would cause the lack of a debugger to create a stackoverflow crash?
What is even stranger is this code appeared to work a few weeks ago. The main changes is the try catch was in another thread and I wasn't using lock(syncLock). Everything is now in one thread however the same crash occurred when run in a BackgroundWorker as well.
UPDATE #2 PROBLEM SEMI-SOLVED
Ok so I rolled back through my commits one by one until it worked. What changed is I went from .NET 3.5 to .NET 4.0
.NET 3.5 does not crash regardless of attaching a debugger or not. .NET 4.0 crashes if a debugger is not attached. To rule out a bug in my code I simply deleted the ConcurrentQueue for my log (the only 4.0 feature I was using) and converted my current code base back to 3.5 and I do not get this error.
To be 100% sure it is an issue with 4.0 I then converted my code base back to 4.0 from 3.5 and left the ConcurrentQueue out (literally just changed the build options and did a rebuild) and the StackOverflow crash is back.
I would prefer to use 4.0, any ideas how to debug this issue?
edit: .NET 4.6.1 also crashes
UPDATE #3
http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html
Apparently pinvokestackimbalance is basically ignored in .NET 3.5, so the problem still exists, it just doesn't crash my application.
Adding the following code to App.Config causes .NET to repair the stack when transitioning back to managed code. A small performance hit but it will fix the problem.
Whilst this does fix the problem, I'd like to know what is wrong with my UnmanagedFunctionPointer to cause the problem in the first place.
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
Edit: this thread isn't a duplicate, the other one is deleted...
Ok so the problem is the calling convention should be StdCall not Cdecl
This makes sense as the generic J2534 API documentation specifies the following header. Although the header file I was supplied does not make this specification.
extern "C" long WINAPI PassThruConnect
(
unsigned long ProtocolID;
unsigned long Flags
unsigned long *pChannelID
)
Where WINAPI is also known as StdCall not Cdecl like most C/C++ libraries would typically use.
.NET 3.5 allows the wrong calling convention and will "fix" the stack. As of 4.0 this is no longer the case and a PinvokeStackImbalance exception is raised.
You can force 4.0 to also fix the stack with the following code added to your App.Config
<configuration>
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>
Or you can simply fix your calling convention by changing Cdecl to StdCall:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID);
Related
I am using slightly modified IDocHostUIHandler from https://stackoverflow.com/a/21699086/592212 in simple one main window test application with only WPF WebBrowser component in that Window. The initialization code is as follows:
public MainWindow()
{
InitializeComponent();
_wbHostHandler = new WebBrowserHostUIHandler(PART_WebBrowser);
_wbHostHandler.Flags |= HostUIFlags.DpiAware;
PART_WebBrowser.Navigate("SOME_URL");
}
There is really nothing else going on in the Application. Still, after running the application, an error is thrown in COM component (therefore, I can not use a debugger to trap it) and 0xc0000409 (STATUS_STACK_BUFFER_OVERRUN) is reported in Event Viewer.
Any ideas of what is causing the error or how to get rid of it?
(Win10 Pro 1703 (build 15063.483) and .NET 4.6.2)
Source Code: https://www.dropbox.com/s/ddob6p7jh4dfsda/UIHostCrashDemo.zip?dl=1
I don't know where you got your WebBrowserHostUIHandler.cs content from but it's wrong. The definition of IDocHostUIHandler simply misses the TranslateAccelerator method.
I guess it's because my initial code used System.Windows.Forms.Message type which is a reference to the System.Windows.Forms (winforms) assembly. If this is such a problem, the method can just be replaced by this if the message is not used (wich is the case in my initial code).
So in the interface you must add this, just after ResizeBorder:
[PreserveSig]
uint TranslateAccelerator(IntPtr msg, ref Guid group, int nCmdID);
And you must implement it anywhere in the code, like this:
uint Native.IDocHostUIHandler.TranslateAccelerator(IntPtr msg, ref Guid group, int nCmdID)
{
return S_FALSE;
}
But again, this is optional, if you want something that works just carefully copy/paste my code from my post and add a reference to System.Windows.Forms if needed.
I've coded a wrapper for CryptoPP which would be used by c# app.
My issue is that when calling to a specific function in my wrapper using PInvoke, throws an exception "Attempted to read or write protected memory...".
Both of them are compiled as x64.
Now.. strange part is that if i compile my wrapper using /MTd or /MDd runtime, the call does not fail and everything works perfectly. But changing the runtime to /MT or /MD would throw the above exception.
I cannot use the /MTd or /MDd option for official use by my customers, as it requires lots of dlls resources to be installed or distributed into the user machine.
cpp code:
extern "C" __declspec(dllexport) int CryptBlock(bool mode, unsigned char type, unsigned char *inData, unsigned char *outData, int dataLen, unsigned char *key, int keyLen);
c# PInvoke:
[DllImport("mydll.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl)]
public static extern int CryptBlock(bool mode, byte type, IntPtr inData, IntPtr outData, int dataLen, IntPtr key, int keyLen);
I have tried modifying my P/Invoke code in various ways:
[In, Out], [Out], ref, ref byte[], byte[] etc... still throwing the exception.
Waiting for my savior...
Thank you.
You are right that you cannot distribute the debug runtime, but in fact the issue is not quite what you think. The license does not permit redistribution of the debug runtime.
The most likely explanation is in fact that your code has a defect. The fact the the defect does not manifest with the debug runtime is simply down to chance. So the correct way to proceed is to track down your defect and fix it.
Consider using a bridge between Managed and Unmanaged code.
It can be debug more easily...
Example:
C++ Unmanaged code:
class ExampleCpp
{
private:
int id;
public:
ExampleCpp();
~ExampleCpp();
const int getId();
};
C++ Managed Code:
public ref class ExampleManagedCpp
{
private:
ExampleCpp* pImpl;
public:
ExampleManagedCpp();
~ExampleManagedCpp();
!ExampleManagedCpp();
};
http://www.codeproject.com/Articles/868230/Cplusplus-CLI-Accessing-a-managed-type-from-unmana
http://blogs.msdn.com/b/soultech/archive/2010/07/27/cli-c_2b002b00_-to-c_2300_-hello-world.aspx
I have a WPF Application, and I must load the DLL cc3260mt.dll
I call it by using LoadLibrary(), but for whatever reason I am getting an ArithmeticException.
Here is what my code looks like :
public partial class MainWindow : Window
{
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
static extern IntPtr FreeLibrary(IntPtr hModule);
public MainWindow()
{
InitializeComponent();
try
{
string cc3260mtPath = "dll/cc3260mt.dll";
IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
}
catch (Exception ex)
{
Console.WriteLine("ERROR : " + ex.Message);
}
} // <-- This is where I get the Exception.
}
When I run my code step by step, I can clearly see that the exception appears when I get out of my MainWindow() class.
Do you guys have any idea what gets me this exception ?
That is the C runtime support library for old Borland C or C++ programs. And yes, it does something that's very incompatible with .NET code in general, and WPF in particular, it reprograms the floating point unit control register. It enables hardware exceptions, triggered when a floating point operation fails. Particularly problematic in WPF because is likes to use Double.NaN a lot. Which generates an FPU exception, the CLR intercepts it and re-raises it as an ArithmeticException.
You will have to undo what this DLL did and restore the FPU control word. This is problematic, .NET doesn't give you direct access to the hardware like that. There is however a trick you can use, the CLR automatically reprograms the FPU when it handles an exception. So you can intentionally generate an exception and catch it. Like this:
IntPtr cc3260Link = LoadLibrary(cc3260mtPath);
try { throw new Exception("Ignore this please, resetting the FPU"); }
catch (Exception ex) {}
Do note the consequence of this, you'll now have the native code running without the exceptions it normally relies on. Maybe that will work.
I tested a lot. But I found no disadvantages of those 2!
But see the accepted answer.
I read here that calling GetLastError in managed code is unsafe because the Framework might internally "overwrite" the last error. I have never had any noticeable problems with GetLastError and it seems for me that the .NET Framework is smart enough not to overwrite it. Therefore I have a few questions on that topic:
in [DllImport("kernel32.dll", SetLastError = true)] does the SetLastError attribute make the Framework store the error code for the use of Marshal.GetLastWin32Error() ?
is there an example where plain GetLastError fails to give the correct result ?
do I really HAVE to use Marshal.GetLastWin32Error() ?
is this "problem" Framework version related ?
public class ForceFailure
{
[DllImport("kernel32.dll")]
static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetVolumeLabel(string lpRootPathName, string lpVolumeName);
public static void Main()
{
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
System.Console.WriteLine("It worked???");
else
{
// the first last error check is fine here:
System.Console.WriteLine(GetLastError());
System.Console.WriteLine(Marshal.GetLastWin32Error());
}
}
}
Producing errors:
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
Console.WriteLine("It worked???");
else
{
// bad programming but ok GetlLastError is overwritten:
Console.WriteLine(Marshal.GetLastWin32Error());
try
{
using (new FileStream("sdsdafsdfsdfs sdsd ", FileMode.Open)) { }
}
catch { }
Console.WriteLine(GetLastError());
}
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
Console.WriteLine("It worked???");
else
{
// bad programming and Marshal.GetLastWin32Error() is overwritten as well:
Console.WriteLine(GetLastError());
try
{
using (new FileStream("sdsdafsdfsdfs sdsd ", FileMode.Open)) { }
}
catch { }
Console.WriteLine(Marshal.GetLastWin32Error());
}
// turn off concurrent GC
GC.Collect(); // doesn't effect any of the candidates
Console.WriteLine(" -> " + GetLastError());
Console.WriteLine(" -> " + GetLastError());
Console.WriteLine(Marshal.GetLastWin32Error());
Console.WriteLine(Marshal.GetLastWin32Error());
// when you exchange them -> same behaviour just turned around
I don't see any difference! Both behave the same except Marshal.GetLastWin32Error stores results from App->CLR->WinApi calls as well and GetLastError stores only results from App->WinApi calls.
Garbage Collection seems not to call any WinApi functions overwriting the last error code
GetLastError is thread-safe. SetLastError stores an error code for each thread calling it.
since when would GC run in my threads ?
You must always use the Marshal.GetLastWin32Error. The main problem is the garbage collector. If it runs between the call of SetVolumeLabel and the call of GetLastError then you will receive the wrong value, because the GC has surely overwritten the last result.
Therefore you always need to specify the SetLastError=true in the DllImport-Attribute:
[DllImport("kernel32.dll", SetLastError=true)]
static extern bool SetVolumeLabel(string lpRootPathName, string lpVolumeName);
This ensures that the marhsallling stub calls immediately after the native function the "GetLastError" and stores it in the local thread.
And if you have specified this attribute then the call to Marshal.GetLastWin32Error will always have the correct value.
For more info see also "GetLastError and managed code" by Adam Nathan.
Also other function from .NET can change the windows "GetLastError". Here is an example which produces different results:
using System.IO;
using System.Runtime.InteropServices;
public class ForceFailure
{
[DllImport("kernel32.dll")]
public static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetVolumeLabel(string lpRootPathName, string lpVolumeName);
public static void Main()
{
if (SetVolumeLabel("XYZ:\\", "My Imaginary Drive "))
System.Console.WriteLine("It worked???");
else
{
System.Console.WriteLine(Marshal.GetLastWin32Error());
try
{
using (new FileStream("sdsdafsdfsdfs sdsd ", FileMode.Open)) {}
}
catch
{
}
System.Console.WriteLine(GetLastError());
}
}
}
Also it seems that this is depended on the CLR which you are using! If you compile this with .NET2, it will produce "2 / 0"; if you switch to .NET 4, it will output "2 / 2"...
So it is depended on the CLR version, but you should not trust the native GetLastError function; always use the Marshal.GetLastWin32Error.
TL;DR
Do use [DllImport(SetLastError = true)] and Marshal.GetLastWin32Error()
perform the Marshal.GetLastWin32Error() immediately after a failing Win32 call and on the same thread.
Argumentation
As i read it, the official explanation why you need Marshal.GetLastWin32Error can be found here:
The common language runtime can make internal calls to APIs that overwrite the GetLastError maintained by the operating system.
To say it in other words:
Between your Win32 call which sets the error, the CLR may "insert" other Win32 calls which could overwrite the error.
Specifying [DllImport(SetLastError = true)] makes sure that the CLR retrieves the error code before the CLR executes any unexpected Win32 calls.
To access that variable we need to use Marshal.GetLastWin32Error.
Now what #Bitterblue found is that these "inserted calls" don't happen often - he couldn't find any. But that's not really surpising. Why? Because it's extremely difficult to "black box test" whether GetLastError works reliably:
you can detect unreliability only if a CLR-inserted Win32 call actually fails in the meantime.
failure of these calls may be dependent on internal/external factors. Such as time/timing, memory pressure, devices, state of computer, windows version...
insertion of Win32 calls by CLR may be dependent on external factors. So under some circumstances the CLR inserts a Win32 call, under others it doesn't.
behavior can change with different CLR versions as well
There's is one specific component - the Garbage collector (GC) - which is known to interrupt a .net thread if there's memory pressure and do some processing on that thread (see What happens during a garbage collection). Now if the GC were to execute a failing Win32 call, this would break your call to GetLastError.
To sum it up, you have a plethora of unknown factors which can influence the reliability of GetLastError. You'll most likely not find an unreliability problem when developing/testing, but it might blow up in production at any time. So do use [DllImport(SetLastError = true)] and Marshal.GetLastWin32Error() and improve your sleep quality ;-)
in [DllImport("kernel32.dll", SetLastError = true)] does the SetLastError attribute make the Framework store the error code for the use of Marshal.GetLastWin32Error() ?
Yes, as is documented in DllImportAttribute.SetLastError Field
is there an example where plain GetLastError fails to give the correct result ?
As documented in Marshal.GetLastWin32Error Method, if the framework itself (e.g. the garbage collector) calls any native method that sets an error value between your calls to the native method and GetLastError you would get the error value of the framework's call instead of your call.
do I really HAVE to use Marshal.GetLastWin32Error() ?
Since you can't ensure that the framework will never call a native method between your call and the call to GetLastError, yes. Also, why not?
is this "problem" Framework version related ?
It could definitely be (e.g. changes in the garbage collector), but it doesn't have to.
I'm writing a C# .NET 3.5 program wich uses the latest MediaInfoLib Dll.
It seems that it causes an exception for some files.
I want to catch those exceptions and ensure my program continues running,
but for some reason I can't catch it with a simple try/catch statement.
PInvoke Methods:
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_New();
[DllImport("MediaInfo.dll")]
private static extern IntPtr MediaInfo_Open(IntPtr Handle,MarshalAs(UnmanagedType.LPWStr)] string FileName);
Usage:
Handle = MediaInfo_New();
try{
MediaInfo_Open(Handle, FileName)
} catch { }
Calling MediaInfo_Open(Handle, FileName) might cause an exception.
Instead of catching the error with the try/catch statement, my program exits and "vshost32-clr2.exe" crashes. (It also crashes as a release build and with no debugger attached)
After searching the web, I found someone who suggested to check "Enable unmanaged code debugging", which only resulted in my program exiting without vshost32-clr2.exe crashing.
Any idea how I can catch the exception?
If the unmanaged DLL is causing the crash (rather than just returning an error code of some kind), then there's no way to catch it. Once you've gone outside of the .NET runtime's control, it's entirely up to the unmanaged code; there's nothing the .NET runtime can do.
I've had a similar problem (with BSTR specifically) but hopefully this will help.
There is a bug in .NET (fixed in 4.0) when internally marshalling strings back from unmanaged code. More Info
The work-around is to change your P/Invoke signature to use an IntPtr and do the string marshalling yourself.
[DllImport("MediaInfo.dll", EntryPoint = "MediaInfo_Open")]
private static extern IntPtr _MediaInfo_Open(IntPtr handle, IntPtr filename);
internal static extern IntPtr MediaInfo_Open(IntPtr handle, string filename)
{
IntPtr stringPtr = Marshal.StringToBSTR(filename);
return _MediaInfo_Open(handle, stringPtr);
}