2017-01-21 2 views
-1

До сих пор моя программа работала неплохо, я хотел запустить valgrind, чтобы быть уверенным, что я не забыл никаких бесплатных/malloc. Тем не менее, Valgrind сообщил об ошибках, где я считаю, что их нет.Ошибка обнаружения Valgrind при распределении с использованием realloc и strdup

Вот фрагмент кода, чтобы воспроизвести ошибку:

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

Я искал other Q & Об этом ответе, обычно люди забывают выделить нулевой байт.

Я знаю, что realloc может вызвать утечку памяти, когда нет памяти, я должен сначала присвоить результат realloc временной переменной, проверить, что возвращаемое значение не равно null, а затем назначить временную переменную моим истинным переменным.

Аптека из возможной утечки при сбое realloc, есть ли ошибки в этой программе?


UPDATE

Спасибо ребята за быстрые ответы.

Для записи здесь исправленный код:

/* 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) 

Добрый день всем.

+3

Ваш второй 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 *)); 

Вы по-прежнему выделяя только один указатель обугленного. Таким образом, вы не можете хранить два указателя; вам необходимо увеличить размер:

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 кода. Это строка, в которой вы назначаете второй элемент name_array, выделив память только для одного элемента.

+0

К сожалению, я думаю, что моя версия gcc тоже (gcc raspbian v4.9.2-10) для этих флагов. В моем недоверии к valgrind я скомпилировал свой код со всеми возможными флагамизационными флагами без результата. Оказалось, что в конце концов вальгринд был прав, как удивительно. –

Смежные вопросы