2017-01-21 8 views
-1

これまでのところ私のプログラムはかなりうまく動いていましたが、valgrindを実行してフリー/ mallocを忘れていないことを確認しました。しかしValgrindはエラーがないと私は信じています。ここでreallocとstrdupを使って割り振ったときに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 &この回答については、通常、人々はnullバイトを割り当てることを忘れてしまいます。

メモリが残っていないときにreallocがメモリリークを引き起こす可能性があることがわかっています。まず、reallocの結果を一時変数に代入し、戻り値がnullでないことを確認してから、

reallocが失敗した場合のリークの可能性がありますが、このプログラムに間違いがありますか?迅速な答えを


UPDATE

みんなありがとう。あなたのすべてに

==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) 

良い一日:

/* 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の出力:ここではレコードの

は修正されたコードです。この(第2)の呼び出しで

+3

2回目のreallocは配列のサイズを増やしません。 –

+0

'name_array = realloc(name_array、sizeof(char *));' => 'name_array = realloc(name_array、sizeof * name_array * ++ nb_names);'。 – Stargateur

+0

また、 'name_array = realloc(name_array、...)'は潜在的なメモリリークです。 'malloc()'が 'NULL'を返さなかったことを確認してください。 –

答えて

1

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

あなたはまだ一つだけchar型のポインタを割り当てています。したがって、2つのポインタを格納することはできません。あなたはサイズを大きくする必要があります:

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

今、あなたは大丈夫でしょう。

p = realloc(p, ..);realloc()が失敗した場合、realloc()のスタイルでメモリリークが発生する可能性があることに注意してください。

また、あなたは(入力されたユーザであることが起こっている場合)pontential書式文字列攻撃を回避するために、フォーマット文字列を使用したほうが良いと思います:

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

エラーが優れてvalgrindのより消毒アドレスによって報告されました。あなたのようなコードをコンパイルした場合:

gcc test.c -fsanitize=address -g 

し、それを実行し、それはあなたのコードの行19にヒープバッファオーバーフローエラーを報告します。これは、1つの要素だけに割り当てられたメモリを持つname_arrayの2番目の要素を割り当てる行です。

+0

残念ながら私のgccのバージョンは、これらのフラグの古い(gcc raspbian v4.9.2-10)古いと思います。 valgrindの不信感の中で、私はすべての可能なfsanitizeフラグを使ってコードをコンパイルしました。バンググラインドが最終的に正しいことが判明した。どれほど驚くべきことだ。 –

関連する問題