Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/265.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用.NET 4.0和3.5时,非托管FunctionPointer会导致堆栈溢出_C#_C++_Exception_Interop_Clr - Fatal编程技术网

C# 使用.NET 4.0和3.5时,非托管FunctionPointer会导致堆栈溢出

C# 使用.NET 4.0和3.5时,非托管FunctionPointer会导致堆栈溢出,c#,c++,exception,interop,clr,C#,C++,Exception,Interop,Clr,我在click处理程序中有一个简单的函数,它有一个try-catch块。如果我在这个try-catch块中抛出异常,它将成功捕获该异常 如果在抛出异常之前对非托管DLL进行调用,则该异常未经处理且未被捕获 未更改的DLL调用在做什么,可能会破坏我的程序异常处理 如果我在调试模式下运行程序,它会捕获异常,即使“异常中断”未选中所有异常。应用程序不会崩溃并按预期运行 如果我以“启动而不调试”的方式运行程序,并在程序崩溃时点击调试,则会出现以下错误“堆栈cookie检测代码检测到基于堆栈的缓冲区溢出”

我在click处理程序中有一个简单的函数,它有一个try-catch块。如果我在这个try-catch块中抛出异常,它将成功捕获该异常

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

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

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

如果我以“启动而不调试”的方式运行程序,并在程序崩溃时点击调试,则会出现以下错误“堆栈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问题半解决

好的,所以我一个接一个地回滚我的提交,直到它起作用。改变的是我从.NET3.5升级到了.NET4.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

显然在.NET3.5中基本上忽略了PinvokesTack不平衡,所以这个问题仍然存在,只是没有使我的应用程序崩溃

将以下代码添加到App.Config会导致.NET在转换回托管代码时修复堆栈。虽然性能受到了小的影响,但它可以解决问题

虽然这确实解决了问题,但我想知道我的UnmanagedFunctionPointer在一开始就导致问题的原因是什么

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


编辑:此线程不是重复的,另一个已删除

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

这是有意义的,因为通用J2534API文档指定了以下标题。虽然我提供的头文件不符合此规范

extern "C" long WINAPI PassThruConnect
(
unsigned long ProtocolID;
unsigned long Flags
unsigned long *pChannelID
)
其中WINAPI也称为StdCall,不像大多数C/C++库通常使用的Cdecl

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

您可以强制4.0也使用添加到App.Config的以下代码修复堆栈

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

有几个致命的异常是.Net代码堆栈损坏无法捕获的,我相信是其中之一。很可能是互操作包装错误,堆栈未对齐。。。或者本机代码很糟糕。好吧,我在托管调用之前添加了Debugger.Launch(),它会引发StackOverflow异常,这无疑会破坏异常处理。为什么从一开始就连接调试器时不会发生这种情况?好的,如果我使用具有相同函数原型的dllimport,我不会得到stackoverflow。当使用非托管函数指针时,我还需要做些什么吗?你应该在你的帖子中添加你找到的信息,以便更多人看到(编辑会将帖子移回主页)。。。因此,在互操作方面有更多经验的人可以回答这个问题。我还建议在DLL中添加函数的C签名,因为这可能有助于回复。(如果我需要这样做,我只需在pinvoke.net上找到类似的函数并复制它的声明方式…)谢谢。更新了更多信息。
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate uint PassThruConnect(uint deviceId, uint protocolId, uint flags, uint baudRate, ref uint channelID);