gpt4 book ai didi

c# - UnmanagedFunctionPointer 在使用 .NET 4.0、3.5 时会导致 stackoverflow

转载 作者:搜寻专家 更新时间:2023-10-31 02:14:19 25 4
gpt4 key购买 nike

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

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

未管理的 DLL 调用在做什么,可能会破坏我的程序异常处理?

如果我在 Debug模式下运行程序,即使所有异常都未选中“异常中断”,它也会捕获异常。应用程序不会崩溃并按预期运行。

如果我以“不调试的方式启动”运行程序并在它崩溃时点击调试,我会收到以下错误“堆栈 cookie 检测代码检测到基于堆栈的缓冲区溢出”

编辑:看起来堆栈溢出破坏了异常处理

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

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

显然 pinvokestackimbalance 在 .NET 3.5 中基本上被忽略了,所以问题仍然存在,它只是没有让我的应用程序崩溃。

将以下代码添加到 App.Config 会导致 .NET 在转换回托管代码时修复堆栈。性能下降很小,但可以解决问题。

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

<configuration> 
<runtime>
<NetFx40_PInvokeStackResilience enabled="1"/>

编辑:这个线程不是重复的,另一个被删除了......

最佳答案

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

这是有道理的,因为通用 J2534 API 文档指定了以下 header 。虽然我提供的头文件没有做这个规范。

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

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

.NET 3.5 允许错误的调用约定并将“修复”堆栈。从 4.0 开始,情况不再如此,并引发了 PinvokeStackImbalance 异常。

您可以强制 4.0 也通过将以下代码添加到您的 App.Config 来修复堆栈

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

关于c# - UnmanagedFunctionPointer 在使用 .NET 4.0、3.5 时会导致 stackoverflow,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40077376/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com