具有realloc的程序在Valgrind中表现不同

时间:2012-12-09 21:24:20

标签: c valgrind realloc

我编写了一个函数,用fgets读取一个字符串,使用realloc()使缓冲区在需要时增长:

char * read_string(char * message){
    printf("%s", message);
    size_t buffsize = MIN_BUFFER;
    char *buffer = malloc(buffsize);
    if (buffer == NULL) return NULL;
    char *p;
    for(p = buffer ; (*p = getchar()) != '\n' && *p != EOF ; ++p)
        if (p - buffer == buffsize - 1) {
            buffer = realloc(buffer, buffsize *= 2) ;
            if (buffer == NULL) return NULL;
        }
    *p = 0;
    p = malloc(p - buffer + 1);
    if (p == NULL) return NULL;
    strcpy(p, buffer);
    free(buffer);
    return p;
}

我编译了程序并尝试了它,并且它按预期工作。但是当我用valgrind运行它时,当读取字符串是> = MIN_BUFFER并且valgrind说:

时,该函数返回NULL
(...)
==18076==  Invalid write of size 1
==18076==    at 0x8048895: read_string (programme.c:73)
==18076==    by 0x804898E: main (programme.c:96)
==18076==  Address 0x41fc02f is 0 bytes after a block of size 7 free'd
==18076==    at 0x402BC70: realloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==18076==    by 0x8048860: read_string (programme.c:76)
(...)
==18076== Warning: silly arg (-48) to malloc()
(...)

我在* p = 0之间添加了一个printf语句;并且p = malloc ...并且它确认传递的arg的值为-48。 我不知道单独启动和使用valgrind时程序不会以相同的方式运行。我的代码中有什么问题,还是只是一个valgrind错误?

3 个答案:

答案 0 :(得分:6)

当您重新分配缓冲区时,指针'p'仍然指向旧缓冲区。

这会破坏内存,并导致将来的分配使用虚假值。

答案 1 :(得分:1)

正如man 3 realloc所说

  

...该功能可能会将内存块移动到新位置。

这意味着什么呢

p = malloc(p - buffer + 1);

是问题所在。如果调用realloc(),缓冲区可能指向一个新的内存和表达式块

(p - buffer)

没有任何意义。

答案 2 :(得分:1)

realloc返回一个指向所请求大小的新缓冲区的指针,其内容与传入的指针相同,假设传入的指针先前由mallocrealloc返回。它不保证它是相同的指针。 Valgrind很可能修改realloc的行为,但将其保持在规范范围内。

由于您要在循环中调整内存大小,因此您可以通过跟踪buffer中的位置作为buffer开头的偏移而不是指针来提供更好的服务。