调试内存损坏问题

7

之前我遇到了C语言(Visual Studio)中动态内存的问题。

我有一个基本可用的程序,但在释放其中一个缓冲区时抛出了运行时错误。这是明显的内存损坏,程序在缓冲区结束后写入了数据。

我的问题是,跟踪下来非常耗时。错误会在内存损坏后很长时间才被抛出,我必须手动调试整个运行过程,找到何时覆盖了缓冲区结尾。

有没有任何工具或方法可以帮助我解决这个问题?如果程序立即崩溃,我将更快地找到问题...

以下是问题的示例:

int *pNum = malloc(10 * sizeof(int));

//                 ||
//                 \/    
for(int i = 0; i < 13; i++)
{
pNum[i] = 3;
}

// error....
free(pNum);

这不是 Visual Studio 中“缓冲区安全检查”编译器选项所做的吗? - stijn
4
不要使用魔术数字? - phant0m
5
@phant0m 这并不是真正的代码,只是一个例子,也不是我的代码...缓冲区是根据数据大小动态分配的,并且计算大小的函数有一个小错误... 此外,我的问题是关于追踪问题,而不是预防它... - AK_
@stijn 它在安全方面有帮助,但不适用于调试...它不会立即崩溃...也不会显示错误... - AK_
4个回答

4
我使用“数据断点”进行调试。在您的情况下,当程序崩溃时,它可能会首先抱怨如下:
堆块00397848在0039789C之后修改了请求大小4c。
然后,重新启动程序,并在地址0039789C处设置一个数据断点。当代码写入该地址时,执行将停止。我经常发现在此时立即找到错误。
如果您的程序重复分配和撤消内存,并且恰好位于此确切地址,则仅禁用撤消即可:
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_DELAY_FREE_MEM_DF);

3
我使用pageheap。这是来自微软的一个工具,可以改变分配器的工作方式。启用pageheap后,当您调用malloc时,分配将舍入到最近的页面(内存块),并在其后放置一个额外的虚拟内存页面,该页面设置为不可读/不可写。您分配的动态内存被对齐,以使您的缓冲区的末尾恰好位于虚拟页面之前的页面的末尾。这样,如果您超出了缓冲区的边缘,通常只有一个字节,调试器可以轻松地捕获它。

2
有没有工具或方法可以帮助追踪这个问题?
是的,这正是静态代码分析器尝试定位的错误类型。例如 splint/PC-Lint
以下是这样的工具列表:http://en.wikipedia.org/wiki/List_of_tools_for_static_code_analysis 编辑:在对您的代码片段尝试splint时,我收到以下警告:
main.c:9:2: 可能的越界存储:pnum[i]
可以想象,这个警告会对您有所帮助。

0

我们的 CheckPointer 工具可以帮助查找内存管理错误。它适用于GCC 3/4和Microsoft C方言。

许多动态检查器只能捕获对象外部的访问,而且仅当对象在堆上分配时才能捕获。CheckPointer将发现堆分配对象中的内存访问错误;无论字段类型如何,在结构体字段末尾之外访问是非法的;大多数动态检查器无法检测此类错误。它还将发现局部变量的边缘访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接