P/Invoke 和内存相关的间歇性崩溃

Posted

技术标签:

【中文标题】P/Invoke 和内存相关的间歇性崩溃【英文标题】:P/Invoke and memory related intermittent crash 【发布时间】:2014-11-18 12:11:03 【问题描述】:

我前段时间实现了这个 API,一切运行良好,直到几周前我注意到它,间歇性崩溃,与 .NET 相关的著名编组“试图读取或写入受保护的内存。这通常是表明其他内存已损坏”。我注意到我打开的应用程序的数量也有一定的模式,所以我假设它与内存有关。但是检查可用内存,它在崩溃时仍然指向健康状态。请看下面的功能:

C++  
__declspec(dllexport) char* xReadData(char *p_buffer, int offset, int size)

    // do nothing
    return p_buffer; 


C#
[DllImport(PathToDll, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr xReadData([Out] IntPtr buffer, int offset, int size);

// SIZE = amount of bytes to read (2^13)
IntPtr pnt = Marshal.AllocHGlobal(SIZE);
...
try
                                
    xReadData(pnt, 0, SIZE); >> crashing on [Managed to Native Transition]  


catch


...
Marshal.FreeHGlobal(pnt);

根据我的分析,它在本机函数完成和再次返回托管代码之间崩溃。

提前致谢。

【问题讨论】:

欢迎来到 Stack Overflow!建议查看提出此类问题的指南:***.com/help/mcve 完全忽略本机代码中的 size 参数当然肯定会造成麻烦。是的,当您执行此操作时,AccessViolations 是正常的。 这是编辑部分的错字。现已更正。 问题仍然存在。我希望我包括了所有需要指出问题所在的部分。 【参考方案1】:
if ((offset>-1) && (offset + size<= MAX_BYTES))

    memcpy(p_buffer, &(input_list[offset]), size);

offset 等于MAX_BYTES 并且size 等于0 时,该条件肯定会抛出异常。

input_list[MAX_BYTES] 超出范围。

另外,我希望你释放缓冲区:-')

【讨论】:

感谢您的回复。这是真的,一个潜在的错误,只是在这种情况下偏移参数总是按值传递并且为 0。我很确定崩溃不在本机代码中,因为我确实分析了它。 我释放了缓冲区,真的。在它崩溃的时候,它甚至没有那么远来释放缓冲区。它只是在本机函数完成和再次返回托管代码之间崩溃。 @Allegro07;调试时使用分治法。开始一件一件地摆脱这些东西。摆脱memcpy,看看崩溃是否仍然存在,如果是?那么那部分与问题无关。为什么你的方法返回的 IntPtr 和你传入的一样? 目前这是c++函数的设计,不是我的作品,我同意这很愚蠢,但这不是重点。我避免了 memcpy 操作并且崩溃仍然存在于某处,但这是一个很好的反馈,以便改进问题输入数据并排除 memcpy。 @Allegro07,我能告诉你的真的不多。创建一个新的测试项目,看看您是否可以重现您遇到的问题。看看不从函数返回任何东西是否会使它变得更好。此外,明确设置 C++ 端的调用约定。不要依赖编译器默认值。 __declspec(dllexport) __cdecl 或其他。改变哪些参数?你总是打电话(0,CONSTANT_SIZE)吗?您是否从不同的线程访问它?您在帖子中所说的这种“某种模式”是什么。

以上是关于P/Invoke 和内存相关的间歇性崩溃的主要内容,如果未能解决你的问题,请参考以下文章

C++/C# 互操作中的内存映射和 P/Invoke 性能

内存相关崩溃:Cocos2d游戏中的3维数组

P/Invoke:内存损坏与指针

与 ntdll.dll 相关的无法解释的崩溃

iOS,未知进程,未知崩溃

[.NET] 平台调用(P/Invoke) 与 DllImport 使用的相关讲解与注意事项,