2i3*_*i3r 9 c# c++ dll dynamic-memory-allocation heap-corruption
我有一个c ++ dll,它为我的主要c#应用程序提供一些功能.在这里,我尝试读取文件,将其加载到内存,然后将一些信息(如指针加载数据和内存块计数)返回到c#.Dll成功将文件读取到内存,但在返回主应用程序时,程序因堆损坏而崩溃(检测到严重错误c0000374).
代码非常简单明了,之前我做过类似的事情没有问题,但是我无法弄清楚是什么原因导致问题,我尝试使用"new,malloc和GlobalAlloc"分配内存,但都没有帮助.代码如下:
C++ MyDll:
typedef unsigned long U32;
extern "C" __declspec(dllexport) int ReadFile(LPSTR Path, U32** DataPtr, U32* Count)
{
FILE *fp;
U32 *Data;
CString tempStr(Path);
long fSize;
if(!(fp = fopen(tempStr, "rb"))) {
return 0;
}
// Obtain File Size;
fseek(fp, 0, SEEK_END);
fSize = ftell(fp);
rewind(fp);
Data = (U32 *)GlobalAlloc(0, fSize);
if(Data == NULL) {
fclose(fp);
return -1;
}
// Copy file into the buffer.
if(!(*Count = fread(Data, sizeof(U32), fSize / sizeof(U32), fp))) {
fclose(fp);
free(Data);
return -2;
}
*DataPtr = (U32 *)Data;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
C#应用:
[DllImport(@"MyDll.dll", CallingConvention= CallingConvention.Cdecl)]
private static extern int ReadFile([MarshalAs(UnmanagedType.LPStr)]string Path, out IntPtr dataPtr, out uint Count);
private void readDump(string Path)
{
uint count = 0;
IntPtr Data = new IntPtr();
try{
if(ReadFile(Path, out Data, out count) == 1) //The Program crashes just right after this statement
{
//Do Something ...
}
}
catch() {}
}
Run Code Online (Sandbox Code Playgroud)
程序在调试和释放模式下崩溃.除非我在加载文件后在调试模式下暂停程序并在"Visual Studio的立即窗口"中调用一些内存块.要加载的文件大小约为64MB,我们在PC上有超过2GB未使用的RAM.
更新:我注意到,他们之前工作的一些第三方程序崩溃了"异常代码:c0000005",还有一些其他奇怪的事情发生在Windows 7(主机)中.所以我在另一个Windows安装中测试了代码,一切看起来都像他们应该的那样工作.所以它可能与Windows 7有关.现在我该如何解决这个问题呢?"sfc/scannow"找不到任何问题.
小智 24
如果您的所有代码确实如上所示,那么我没有看到问题.但是,当我遇到这个问题时,有时它因为malloc/new /的任何东西检测到堆损坏,通常这个损坏已经发生在程序中,但是崩溃一直延迟到下一次调用new/malloc.
如果您在执行上述操作并崩溃之前读取其他文件,或者分配或释放其他缓冲区,我会在那里寻找问题.也许在你写入缓冲区的任何地方抛出一堆断言,检查边界以及你要为溢出写的内容.对不起,这不是具体的答案,我没有足够的代表留下这个建议作为评论.
我参加聚会迟到了,但我还是走了。
我从自己的程序中收到了这个错误代码,这让我看到了这篇文章。在 Windows 7 中,我设置的数组位置超出范围,导致下一次分配使程序崩溃。我通过使用 MinGW 的 gcc 的 -g 标志进行编译,然后使用 gdb 运行程序,发现了错误。您在此处的某个位置读取或写入无效位置,并且下一次分配会出现堆损坏。我通过边界检查迭代器解决了我的问题,但这似乎不是这里的问题。
C 程序的主要问题:
FILE_SIZE % 4 == 1则有 3 个字节不属于您分配的数据的一部分,但在您查看最终元素时会被访问u32 数组的。解决方案:
该版本的软件可能在转换时做了一些额外的工作,以便写入超出范围的位置,或者 C# 进行了一些额外的分配调用来执行相同的操作(我不熟悉 C# 的编译方式以及哪些指令会更改它)可能会强加)。
一些查找 4 的下一个倍数的代码:
size_t diff, rfSize = fSize; /* size_t is preferable for array sizes and indexes,
* but matching to fSize's data type will work and
* ensures no truncation occurs. */
/* Only if this is not already a multiple of 4 */
if (diff = fSize % 4)
/* Mod gives the remainder by division by 4, which is also the difference between
* fSize and the next multiple of 4. */
rfSize= fSize + diff;
Run Code Online (Sandbox Code Playgroud)