从C ++回调访问C#函数的访问冲突异常/崩溃.

问题描述:

所以我有一个本机的第三方C ++代码库(.lib和.hpp文件),我曾用它们在C ++/CLI中构建包装程序,最终在C#中使用.

So I have a native 3rd party C++ code base I am working with (.lib and .hpp files) that I used to build a wrapper in C++/CLI for eventual use in C#.

从调试模式切换到发布模式时,我遇到了一个特殊的问题,因为当回调的代码返回时,我会收到访问冲突异常.

I've run into a particular problem when switching from Debug to Release mode, in that I get an Access Violation Exception when a callback's code returns.

原始hpp文件中用于回调函数格式的代码:

The code from the original hpp files for callback function format:

typedef int (*CallbackFunction) (void *inst, const void *data);

来自C ++/CLI包装器的用于回调函数格式的代码:(我将解释一下为什么立刻声明两个)

Code from the C++/CLI Wrapper for callback function format: (I'll explain why I declared two in a moment)

public delegate int ManagedCallbackFunction (IntPtr oInst, const IntPtr oData);
public delegate int UnManagedCallbackFunction (void* inst, const void* data);

-很快,我声明了第二个"UnManagedCallbackFunction"的原因是是我试图创建一个中介"包装中的回调,因此链从Native C ++更改为> C#到本机C ++的版本> C ++/CLI包装器> C#...完全公开,问题仍然存在,它只是被直接推送到C ++/CLI包装器中了(返回).

--Quickly, the reason I declared a second "UnManagedCallbackFunction" is that I tried to create an "intermediary" callback in the wrapper, so the chain changed from Native C++ > C# to a version of Native C++ > C++/CLI Wrapper > C#...Full disclosure, the problem still lives, it's just been pushed to the C++/CLI Wrapper now on the same line (the return).

最后,来自C#的崩溃代码:

And finally, the crashing code from C#:

public static int hReceiveLogEvent(IntPtr pInstance, IntPtr pData)
{
Console.WriteLine("in hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);

// provide object context for static member function
helloworld hw = (helloworld)GCHandle.FromIntPtr(pInstance).Target;
if (hw == null || pData == null)
{
Console.WriteLine("hReceiveLogEvent: received null instance pointer or null data\n");
return 0;
}

// typecast data to DataLogger object ptr
IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataLoggerWrap(pData)));
DataLoggerWrap dlw = (DataLoggerWrap)GCHandle.FromIntPtr(ip2).Target;

//Do Logging Stuff

Console.WriteLine("exiting hReceiveLogEvent...");
Console.WriteLine("pInstance: {0}", pInstance);
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("Setting pData to zero...");
pData = IntPtr.Zero;
pInstance = IntPtr.Zero;
Console.WriteLine("pData: {0}", pData);
Console.WriteLine("pInstance: {0}", pInstance);

return 1;
}

完成对控制台的所有写操作,然后在返回时看到可怕的崩溃:

All writes to the console are done and then we see the dreaded crash on the return:

helloworld.exe中0x04d1004c处未处理的异常:0xC0000005:访问冲突读取位置0x04d1004c.

Unhandled exception at 0x04d1004c in helloworld.exe: 0xC0000005: Access violation reading location 0x04d1004c.

如果我从这里进入调试器,我所看到的就是调用堆栈上的最后一个条目是:> "04d1004c()";其十进制值为80805964

If I step into the debugger from here, all I see is that the last entry on the call stack is: > "04d1004c()" which evaluates to a decimal value of: 80805964

只有在您看到显示以下内容的控制台时,这才很有趣:

Which is only interesting if you look at the console which shows:

entering registerDataLogger
pointer to callback handle: 790848
fp for callback: 2631370
pointer to inst: 790844
in hReceiveLogEvent...
pInstance: 790844
pData: 80805964
exiting hReceiveLogEvent...
pInstance: 790844
pData: 80805964
Setting pData to zero...
pData: 0
pInstance: 0

现在,我知道在调试和发布之间,Microsoft世界中有些事情大不相同.我当然担心字节填充和变量的初始化,因此,如果我在这里没有提供某些内容,请告诉我,我将添加到(已经很久了)帖子中.我也认为托管代码可能不会释放所有所有权,然后本机C ++东西(我没有代码)可能试图删除或杀死pData对象,从而使应用程序崩溃.

更全面的披露,在调试模式下一切正常(貌似)!

Now, I know that between debug and release some things are quite different in the Microsoft world. I am, of course worried about byte padding and initialization of variables, so if there is something I am not providing here, just let me know and I'll add to the (already long) post. I also think the managed code may NOT be releasing all ownership and then the native C++ stuff (which I don't have the code for) may be trying to delete or kill off the pData object, thus crashing the app.

More full disclosure, it all works fine (seemingly) in Debug mode!

一个真实的头问题,需要任何帮助!

A real head scratch issue that would appreciate any help!

我想这与/OPTIMIZATION标志无关在DEBUG构建中已存在(或已关闭),并在发布模式中进行了/rely-optimize-this. /optimization标志集下的JIT和GC行为不同.

尝试添加'volatile'(http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.71%29.aspx)并将该部分标记为关键或不要对其进行优化"部分.另一条路径(我想)是-WinDBG和低级调试(毕竟并不难)
I guess it something have to do with /OPTIMIZATION flag that don't exist (or switched off) in DEBUG build and /really-optimize-this in Release mode. The difference is in JIT and GC behavior under the /optimization flag set.

 Try to add 'volatile' ( http://msdn.microsoft.com/en-us/library/x13ttww7%28VS.71%29.aspx ) and mark the section as critical or 'do-not-optimize-it' section. Another path (I guess) is - WinDBG and low-level debugging (it's not so hard after all)