Неинициализированное значение было создано распределением кучи

Я преследовал эту ошибку, и я просто не понимаю ее. Я забыл какой-то базовый C или что-то в этом роде?

==28357== Conditional jump or move depends on uninitialised value(s)
==28357==    at 0x4C261E8: strlen (mc_replace_strmem.c:275)
==28357==    by 0x4E9280A: puts (ioputs.c:36)
==28357==    by 0x400C21: handlePath (myshell.c:105)
==28357==    by 0x400B17: handleInput (myshell.c:69)
==28357==    by 0x400AAD: acceptInput (myshell.c:60)
==28357==    by 0x4009CF: main (myshell.c:33)
==28357==  Uninitialised value was created by a heap allocation
==28357==    at 0x4C25153: malloc (vg_replace_malloc.c:195)
==28357==    by 0x400BDE: handlePath (myshell.c:99)
==28357==    by 0x400B17: handleInput (myshell.c:69)
==28357==    by 0x400AAD: acceptInput (myshell.c:60)
==28357==    by 0x4009CF: main (myshell.c:33)
==28357==

(095) void handlePath(char *input) {
(096)     if(DEBUG_ON) { printf("%s%s\n", "DEBUG_HANDLEPATH: ", input); }
(097)
(098)     char *inputCopy = NULL;
(099)     inputCopy = (char *)malloc((strlen(input)+1)*sizeof(char));
(100)
(101)     if(inputCopy==NULL) {
(102)         die("malloc() failed in handlePath()");
(103)     }
(104)     strncpy(inputCopy, input, strlen(input)*sizeof(char));
(105)     printf("%s\n", inputCopy);
(106)     free(inputCopy);
(107)     return;
(108) }

Строка 96 печатает параметр "char * input" просто отлично (DEBUG_ON == 1), но строка 105 выплевывает ошибки valgrind (она отлично печатает на консоли). "char * input" происходит от getline(), захватывая строку ввода, а в случае этой функции будет что-то вроде "path/test/path" без кавычек. Я могу печатать и манипулировать им просто в предыдущих функциях. Что неинициализировано о "char * inputCopy"? Есть идеи? Спасибо заранее!

Ответы

Ответ 1

У вас есть две ошибки в строке 104,

strncpy(inputCopy, input, strlen(input)*sizeof(char));

Вам нужно предоставить strncpy место для завершения null, поэтому оно должно быть strlen(input)+1 strncpy не гарантирует, что выходной буфер не будет завершен, что похоже на ошибку в strncpy, но это не так. Он был разработан таким образом. То, что было создано strncpy, это скопировать строку в выходной буфер, а затем заполнить остальную часть буфера нулями. Он не разработан как "безопасный strcpy"

Другая ошибка заключается в том, что strncpy принимает число символов, а не количество байтов, поэтому неверно умножать на sizeof(char).. Поскольку sizeof (char) == 1, это на самом деле не вызывает проблем, но по-прежнему остается неправильным намерением.

Вы были правильно умножить на sizeof(char) в malloc в строке 99, так как malloc требуется количество байтов.

Ответ 2

strncpy не будет помещать символ окончания 0, поскольку он копирует не более N символов (где N - это параметр 3). Поскольку вы указали длину и не включили +1 для завершения 0, она не была добавлена.

Итак, если у вас есть буфер из N байтов, правильное использование strncpy таково:

strncpy(dest, src, N - 1);
dest[N - 1] = '\0';

strncpy - странная функция. Кроме того, что не обещаю написать завершающий 0, он всегда будет писать ровно N символов в буфер назначения. Если src меньше, то N, strncpy на самом деле займет время, чтобы заполнить весь остаток буфера 0.

Ответ 3

Я считаю, что ваш strncpy не помещает завершающий нулевой символ в конец строки, поэтому printf запускается с конца выделенной памяти.