Valgrind在使用realloc和strdup进行分配时检测到错误

时间:2017-01-21 14:15:09

标签: c memory valgrind

到目前为止,我的程序运行得很好,我想运行valgrind以确保我没有忘记任何free / malloc。然而,Valgrind在我认为没有的情况下报告错误。

这是重现错误的代码段:

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

int main()
{
    /* Init the array to NULL for realloc */
    char **name_array = NULL;
    int nb_names =0;

    /* Allocate the first name and add it to the array */
    name_array = realloc(name_array, sizeof(char *));
    name_array[nb_names] = strdup("Hello World!\n");
    nb_names++;


    /* Allocate the second name and add it to the array */
    name_array = realloc(name_array, sizeof(char *));
    name_array[nb_names] = strdup("This is a test!\n");

    /* Print the names */
    printf (name_array[0]);
    printf (name_array[1]);

    /* Free the strdup'd names and the array */
    free(name_array[0]);
    free(name_array[1]);
    free(name_array);
}

这是程序输出:

Hello World!
This is a test!

这是Valgrind输出:

==31585== Memcheck, a memory error detector
==31585== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==31585== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==31585== Command: ./a.out --leak-check=full
==31585== 
==31585== Invalid write of size 4
==31585==    at 0x10538: main (in /home/pi/tmp/a.out)
==31585==  Address 0x49830a4 is 0 bytes after a block of size 4 alloc'd
==31585==    at 0x48358A0: realloc (vg_replace_malloc.c:632)
==31585==    by 0x10517: main (in /home/pi/tmp/a.out)
==31585== 
Hello World!
==31585== Invalid read of size 4
==31585==    at 0x10554: main (in /home/pi/tmp/a.out)
==31585==  Address 0x49830a4 is 0 bytes after a block of size 4 alloc'd
==31585==    at 0x48358A0: realloc (vg_replace_malloc.c:632)
==31585==    by 0x10517: main (in /home/pi/tmp/a.out)
==31585== 
This is a test!
==31585== Invalid read of size 4
==31585==    at 0x10578: main (in /home/pi/tmp/a.out)
==31585==  Address 0x49830a4 is 0 bytes after a block of size 4 alloc'd
==31585==    at 0x48358A0: realloc (vg_replace_malloc.c:632)
==31585==    by 0x10517: main (in /home/pi/tmp/a.out)
==31585== 
==31585== 
==31585== HEAP SUMMARY:
==31585==     in use at exit: 0 bytes in 0 blocks
==31585==   total heap usage: 4 allocs, 4 frees, 39 bytes allocated
==31585== 
==31585== All heap blocks were freed -- no leaks are possible
==31585== 
==31585== For counts of detected and suppressed errors, rerun with: -v
==31585== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

我已经在其他Q&amp; A中搜索了这个答案,通常人们会忘记分配空字节。

我知道当没有内存时,realloc会导致内存泄漏,我应该首先将realloc的结果分配给临时变量,检查返回的值是否为null然后将临时变量分配给我的真实变量。

在realloc失败时可能发生泄漏的公寓,这个程序有什么错误吗?

更新

谢谢你们的快速回答。

这里的记录是更正后的代码:

    /* Allocate the first name and add it to the array */
    name_array = realloc(name_array, sizeof(char *) * ++nb_names);
    name_array[nb_names -1] = strdup("Hello World!\n");


    /* Allocate the second name and add it to the array */
    name_array = realloc(name_array, sizeof(char *) * ++nb_names);
    name_array[nb_names -1] = strdup("This is a test!\n");

    /* Print the names */
    printf (name_array[0]);
    printf (name_array[1]);

valgrind输出:

==32105== Memcheck, a memory error detector
==32105== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==32105== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==32105== Command: ./a.out
==32105== 
Hello World!
This is a test!
==32105== 
==32105== HEAP SUMMARY:
==32105==     in use at exit: 0 bytes in 0 blocks
==32105==   total heap usage: 4 allocs, 4 frees, 43 bytes allocated
==32105== 
==32105== All heap blocks were freed -- no leaks are possible
==32105== 
==32105== For counts of detected and suppressed errors, rerun with: -v
==32105== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

大家好日子。

2 个答案:

答案 0 :(得分:1)

通过此(第二)电话:

name_array = realloc(name_array, sizeof(char *));

您仍然只分配一个字符指针。所以,你不能存储两个指针;你需要增加尺寸:

name_array = realloc(name_array, 2 * sizeof *name_array);

现在,你没事。

请注意,如果p = realloc(p, ..);失败,realloc()样式的realloc()可能会导致内存泄漏。

此外,您最好使用格式字符串来避免格式​​化字符串攻击(如果它将被用户输入):

   /* Print the names */
    printf ("%s\n", name_array[0]);
    printf ("%s\n", name_array[1]);

答案 1 :(得分:0)

地址清理程序报告的错误比valgrind更好。如果您编译代码如下:

gcc test.c -fsanitize=address -g

然后运行它,它将在代码的第19行报告堆缓冲区溢出错误。这是您为name_array分配第二个元素的行,该元素仅为一个元素分配了内存。