Malloc 错误:释放对象的校验和不正确

Malloc Error: incorrect checksum for freed object

提问人:None 提问时间:10/24/2008 最后编辑:j0kNone 更新时间:9/18/2012 访问量:21460

问:

我正在努力为一项任务实现尾巴。我让它正常工作,但是我似乎在随机时间从免费收到错误。

我看不出,要把它追溯到一个模式或除此之外的任何东西都是一致的。

例如,如果我将我的程序称为“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;
}
C 调试 指针 malloc

评论

0赞 Dre 10/24/2008
插槽 0 还是 1 基于?插槽永远不会超过 nlines-1,对吗?
0赞 None 10/24/2008
正确的模数会自动回到 0 左右
0赞 Rasmus Faber 10/24/2008
您使用的是哪种编译器和调试器?根据这一点,他们可能会在调试问题时提供一些帮助。
0赞 Ben Combee 10/24/2008
我建议用 lines = (char **) calloc(nlines, sizeof(char *));calloc 的优点是内存为您归零,因此您将从所有 NULL 指针开始。

答:

0赞 Remo.D 10/24/2008 #1

我不确定它是否相关,但这两行对我来说似乎很可疑:

  *(lines + slot) = (char *) malloc(len * sizeof(char));
  if((lines + slot) == NULL) exit(EXIT_FAILURE);

您首先将 malloc 的返回值分配给,然后检查 ,如果后者为 NULL,则您取消了对 NULL 指针的引用!lines[slot](lines+slot)

此外,如果 lines[slot] (your *(lines+slot)) 不为 null,则在将 malloc() 的结果分配给它时,您将泄漏内存。

我假设是一个 *lines[]' 并且插槽在允许的边界内!lineschar

0赞 Windows programmer 10/24/2008 #2

我同意 remo 对这两行的怀疑,但不同意 remo 偏离的切线。我们应该分享发现这个错误的功劳。

*(lines + slot) = some value
if((lines + slot) == NULL) then die
should be
if(*(lines + slot) == NULL) then die

评论

0赞 Windows programmer 10/24/2008
嘿,当我编辑这个答案时,你编辑了你的源代码。在这种情况下,您的错误可能位于您尚未编辑的程序的其他部分......
0赞 None 10/24/2008
我实际上已经修好了......这不是导致我来自 malloc 的错误的原因
4赞 Rasmus Faber 10/24/2008 #3

如果可以使用特定的输入参数一致地重现问题,则应按如下方式进行调试:

  • 首先调试到导致问题的精确空闲。
  • 然后弄清楚即将释放的内存何时被恶意释放。
  • 接下来,调试到内存被恶意定位的位置。
  • 在内存查看器中找到分配的内存块。记下块的开始和结束。在块之前和之后可能有一个称为保护块的特殊值。
  • 现在单步执行代码,直到内存被释放。在某些时候,您的代码应该错误地覆盖保护块。这是令人反感的说法。

请注意,问题很可能出在程序的完全不同的部分。即使报告错误的是这个自由的,覆盖保护块的代码也可以在任何地方。

评论

0赞 None 10/24/2008
包含 null,您看到的代码是我在指针上操作的唯一位置。很奇怪。
0赞 Rasmus Faber 10/24/2008
其他一些代码可能正在其分配的内存之外写入到块周围的保护值中。这就是为什么你需要单步执行 malloc 和 free 之间的所有代码。在某些时候,某些代码将覆盖其中一个保护值。
1赞 Todd 10/24/2008 #4

我的第一个问题是你如何计算len?它只是 strlen 还是包括 \0 终结器的空间?我认为你可能在你的 strcpy 中超出了你的分配。不良行为往往会发生在单词边界上,并且看起来是随机的。此外,请检查以确保源字符串以 null 结尾。如果您在读取端犯了错误并且没有终止它们。然后 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;

您可以在其中引入调试非常糟糕的范围问题。

7赞 JayG 10/24/2008 #5

例程的写入超出了分配的行缓冲区。

作为参数传递的行的大小(即“len”)可能不包括 NUL 终止符。当你调用 malloc 复制行(即“s”)时,你需要为字符串终止符分配一个额外的字节:

 *(lines + slot) = (char *) malloc((len + 1) * sizeof(char));

评论

3赞 Windows programmer 10/27/2008
这个答案是如何被接受的?在这个答案发布前一天,原来的发帖人对我的回答发表了评论,说“null 由调用函数解释。