UnmanagedFunctionPointer在使用.net 4.0、3.5时导致stackoverflow

本文关键字:5时 stackoverflow net UnmanagedFunctionPointer | 更新日期: 2023-09-27 18:13:15

我有一个简单的函数内部的点击处理程序,有一个try catch块。如果我在try catch块中抛出异常,它会成功捕获异常。

如果在抛出异常之前调用非托管DLL,则异常未被处理且未被捕获。

什么是未修改的DLL调用做可能打破我的程序异常处理?

如果我在调试模式下运行程序,它会捕获异常,即使对所有异常都不勾选"中断异常"。应用程序不会崩溃并按预期运行。

如果我以"start without debugging"的方式运行程序并在它崩溃时点击debug,我会得到以下错误"Stack cookie instrumentation code detected a Stack -based buffer overrun"

编辑:

似乎堆栈溢出破坏了异常处理

我附上了一个简化的程序来导致崩溃。

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);

如果我用以下内容替换对UnmanagedFunctionPointer PassThurConnect的调用,则不会发生崩溃

[DllImport("op20pt32.dll", EntryPoint = "PassThruConnect", CallingConvention = CallingConvention.Cdecl)]
public static extern uint PassThruConnect2(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelId);

是否有一些我没有执行,或者我在分配UnmanagedFunctionPointer时执行不正确,这会导致缺乏调试器来创建stackoverflow崩溃?

更奇怪的是,这段代码几周前似乎还能正常工作。主要的变化是try catch在另一个线程中,我没有使用lock(syncLock)。现在一切都在一个线程中,但是在BackgroundWorker中运行时也发生了相同的崩溃。

更新#2问题半解决

好的,所以我一个接一个地回滚我的提交,直到它工作。改变的是我从。net 3.5到。net 4.0

。.NET 3.5无论是否附加调试器都不会崩溃,.NET 4.0如果不附加调试器就会崩溃。为了排除代码中的错误,我简单地删除了日志的ConcurrentQueue(我使用的唯一4.0特性),并将当前的代码库转换回3.5,我没有得到这个错误。

为了100%确定这是4.0的问题,我然后将我的代码库从3.5转换回4.0,并离开了ConcurrentQueue(字面上只是改变了构建选项并进行了重建),并且StackOverflow崩溃回来了。

我更喜欢使用4.0,有什么想法如何调试这个问题吗?

.NET 4.6.1也会崩溃

更新# 3 http://codenition.blogspot.com.au/2010/05/pinvokestackimbalance-in-net-40i-beg.html

显然pinvokestack失衡在。net 3.5中基本上被忽略了,所以问题仍然存在,它只是没有使我的应用程序崩溃。

将以下代码添加到App.Config会导致。net在转换回托管代码时修复堆栈。对性能的影响很小,但是可以解决这个问题。

虽然这确实解决了问题,但我想知道我的UnmanagedFunctionPointer有什么问题,首先会导致问题。

<configuration> 
  <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/>
编辑:这个线程不是重复的,另一个被删除了…

UnmanagedFunctionPointer在使用.net 4.0、3.5时导致stackoverflow

问题是调用约定应该是StdCall而不是Cdecl

这是有意义的,因为通用的J2534 API文档指定了以下头。尽管我提供的头文件没有做出这个规范。

extern "C" long WINAPI PassThruConnect
(
unsigned long ProtocolID;
unsigned long Flags
unsigned long *pChannelID
)

WINAPI也被称为StdCall,而不是像大多数C/c++库通常使用的Cdecl。

。NET 3.5允许错误的调用约定,并将"修复"堆栈。从4.0开始,这不再是这种情况,并且会引发pinvokestack失衡异常。

你可以通过在你的App.Config

中添加以下代码来强制4.0修复堆栈
<configuration> 
  <runtime> 
    <NetFx40_PInvokeStackResilience enabled="1"/>

或者您可以通过将Cdecl更改为StdCall:

来修复调用约定。
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID);