Malloc 错误:已释放对象的校验和不正确
题
我正在努力实现一项作业的 tail 。我让它工作正常,但我似乎随机地从免费中收到错误。
我看不出,追踪它的模式或除它之外的任何东西是一致的。
例如,如果我将我的程序称为“tail -24 test.in”,我会在多次运行的同一行中收到错误的校验和错误。然而,对于不同的文件,甚至不同的打印行数,我将毫无错误地返回。
关于如何追踪问题的任何想法,我已经尝试调试了几个小时但无济于事。
这是有问题的代码:
lines 被定义为 char** 并被 malloc 为:
lines = (char**) malloc(nlines * sizeof(char *));
void insert_line(char *s, int len){
printf("\t\tLine Number: %d Putting a %d line into slot: %d\n",processed,len,slot);
if(processed > numlines -1){//clean up
free(*(lines+slot));
*(lines + slot) = NULL;
}
*(lines + slot) = (char *) malloc(len * sizeof(char));
if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
strcpy(*(lines+slot),s);
slot = ++processed % numlines;
}
解决方案
您的例程正在写入超出分配的行缓冲区。
作为参数传递的行的大小(即“len”)可能不包括NUL终止符。当你调用malloc复制行(即“s”)时,你需要为字符串终止符分配一个额外的字节:
*(lines + slot) = (char *) malloc((len + 1) * sizeof(char));
其他提示
如果您可以使用特定的输入参数一致地重现问题,则应该像这样进行调试:
- 首先调试到导致问题的精确空闲位置。
- 然后找出即将释放的内存何时被分配。
- 接下来,调试到内存分配的位置。
- 在内存查看器中找到已分配的内存块。请注意块的开头和结尾。可能有一个特殊的值称为 防护块 就在块之前和之后。
- 现在逐步执行代码,直到内存被释放。在某些时候,您的代码可能会错误地覆盖保护块。 这就是令人反感的言论。
请注意,问题很可能出在程序的完全不同的部分。尽管报告错误的是这个空闲的代码,但覆盖保护块的代码可以在任何地方。
我的第一个问题是你如何计算len?它只是strlen还是包含\ 0终止符的空间?我认为你可能会在你的strcpy中超出你的分配。不良行为往往会出现在单词边界上并且随机出现。另外,请检查以确保源字符串为空终止。如果你在阅读方面犯了错误并且没有终止它们。然后strcpy可能会随机覆盖一些东西。
*(lines + slot) = (char *) malloc(len * sizeof(char));
if(*(lines + slot) == NULL) exit(EXIT_FAILURE);
strcpy(*(lines+slot),s);
也许试试:
lines[slot] = (char *) malloc((len + 1) * sizeof(char));
if(lines[slot] == NULL) exit(EXIT_FAILURE);
if(strlen(s) <= len){
strcpy(lines[slot],s);
}
else{
/* do something else... */
}
就一般形式而言,我还鼓励你做一些风格上的改变,使整个事情更具可读性,更容易理解,并且能够抵御错误。
指针算法是有效且有趣的,但我认为如果使用数组形式,你的意图会更清晰:
free(lines[slot]);
lines[slot] = NULL;
而不是
free(*(lines+slot));
*(lines + slot) = NULL;
我也鼓励你使用更少的静力学。在数据结构中通过它们很容易,并将它们传递给您的访问器和更改器。事情发生的地方变得更加清楚,这会妨碍你做以下事情:
static int numlines = 0;
void insert_line(char *s, int len){
int numlines = 5;
您可以在其中介绍仅对调试感到悲惨的范围问题。
nlines和numlines是否具有相同的值?
在第二个参数中传递长度时,insert_line的调用者是否允许尾随NUL的空间?
我不确定它是否相关,但这两行对我来说似乎很可疑:
*(lines + slot) = (char *) malloc(len * sizeof(char));
if((lines + slot) == NULL) exit(EXIT_FAILURE);
首先将malloc的返回值分配给 lines [slot]
,然后检查(lines + slot)
,如果后者为NULL,则取消引用NULL指针!
如果行[slot](你的*(行+插槽))不为null,当你将malloc()的结果赋给它时,你将泄漏内存。
我假设 lines
是 char
* lines []`并且slot在允许的范围内!
我同意雷莫对这两条线的怀疑,但不同意雷莫的切线。我们应该分享信用来发现这个错误。
*(lines + slot) = some value
if((lines + slot) == NULL) then die
should be
if(*(lines + slot) == NULL) then die