【问题标题】:Double free or corruption (!prev) with one malloc() and one free() in a loop循环中一个 malloc() 和一个 free() 的双重释放或损坏 (!prev)
【发布时间】:2015-10-02 07:00:16
【问题描述】:

我正在通过编写 string.h 库的函数来练习 C。但是我目前遇到了一个我不明白的问题。当我执行我的程序时,它会崩溃并显示以下消息:

双重释放或损坏 (!prev)

我尝试使用 Valgrind,但似乎没有出现该错误。

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

char * duplicateString(const char * str) {
    size_t strLength = strlen(str);

    char * duplicatedString = malloc(strLength);
    if(duplicatedString == NULL)
        exit(EXIT_FAILURE);

    // +1 to copy '\0'
    strncpy(duplicatedString, str, strLength + 1);

    return duplicatedString;
}

void test_duplicateString()
{
  const char * src = "abc";
  char buf[1024];
  int i, j;
  char * temp = duplicateString(src);

  assert((strcmp((src),(temp)) == 0));
  assert(src != temp);
  free(temp);

  for(i = 0; i < 1024; ++i)
  {
    for(j = 0; j < i; ++j)
      buf[j] = (char) ('a' + (j % 26));
    buf[i] = '\0';

    temp = duplicateString(buf);
    assert((strcmp((buf),(temp)) == 0));
    free(temp);
  }
}

int main()
{
    test_duplicateString();
    return 0;
}

根据 GDB,当 i=136 时,此错误总是发生在第 38 行。 例如为什么在 i=136,而不是之前?

#0  0x00007ffff7a6a5f8 in raise () from /usr/lib/libc.so.6
No symbol table info available.
#1  0x00007ffff7a6ba7a in abort () from /usr/lib/libc.so.6
No symbol table info available.
#2  0x00007ffff7aa905a in __libc_message () from /usr/lib/libc.so.6
No symbol table info available.
#3  0x00007ffff7aae9a6 in malloc_printerr () from /usr/lib/libc.so.6
No symbol table info available.
#4  0x00007ffff7aaf18e in _int_free () from /usr/lib/libc.so.6
No symbol table info available.
#5  0x000000000040093e in test_duplicateString () at /media/sf_data/Cours/Polytech/DI3/Langage_C/DoubleFreeTest/main.c:38
        src = 0x400a10 "abc"
        buf = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef\000\344\377\367\377\177\000\000\240\345\377\377\377\177\000\000x\030\375\367\377\177\000\000\000\000\000\000\000\000\000\000\230\331\377\367\377\177\000\000`\346\377\377\377\177\000\000?M\336\367\377\177\000\000\001\000\000\000\000\000\000\000"...
        i = 136
        j = 136
        temp = 0x602010 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef"
        __PRETTY_FUNCTION__ = "test_duplicateString"
#6  0x0000000000400979 in main () at /media/sf_data/Cours/Polytech/DI3/Langage_C/DoubleFreeTest/main.c:44
No locals.

【问题讨论】:

  • char * duplicatedString = malloc(strLength); 应该是char * duplicatedString = malloc(strLength+1);
  • malloc(strLength +1 )
  • char * duplicatedString = malloc(strLength);。不应该是malloc(strLength + 1)吗?
  • 我很惊讶你说 valgrind 没有发现错误。它当然适合我:==8066== Invalid write of size 1; at 0x402D763: strncpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so); by 0x8048745: test_duplicateString (in /tmp/a.out)
  • 注:简化strncpy(duplicatedString, str, strLength + 1); return duplicatedString; --> return memcpy(duplicatedString, str, strLength + 1);

标签: c free


【解决方案1】:

要将所有 cmets 所说的内容放入答案中,在您的函数 duplicateString() 中,您没有分配足够的内存来容纳字符串空字符。

所以当你这样做时

strncpy(duplicatedString, str, strLength + 1);

您复制的内容超出了缓冲区的容量。解决方案显然是将缓冲区大小增加 1。

char * duplicatedString = malloc(strLength + 1);

【讨论】:

  • 哦,是的。它有效,当然现在看起来像是初学者的错误。但现在我有一个更有趣的问题。有一点我不明白。由于我没有分配足够的块,free() 怎么会触发错误呢?不应该只释放分配的块吗?我可以理解为什么在数组之外设置一个数字不能使程序崩溃,但是,这不是。
  • @MrG0z 我不确定具体细节(我不知道malloc 的所有复杂性),但这可能是因为malloc 分配的内存比请求的多,并且使用了额外的内存用于某种簿记的内存。当你调用free时,读取了这个记账数据,并确定内存已损坏(你在上面写了)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
  • 1970-01-01
  • 2020-12-30
  • 2010-10-27
  • 2012-05-20
  • 1970-01-01
相关资源
最近更新 更多