Может ли жалоба Вальгринда на неинициализированные значения быть ложноположительной? - PullRequest
10 голосов
/ 14 июня 2011

Итак, я учил себя Си, и в надежде научиться правильно управлять памятью с самого начала и писать лучший код, я запускал Valgrind для всего.Это помогло мне с утечками памяти, но я не могу избавиться от этой ситуации «Условный переход или перемещение зависит от неинициализированного значения (й) / Неинициализированное значение было создано распределением кучи», хотя я сузил егок этому блоку кода:

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

int main()    
{  
    char* test = (char*) malloc(3);
    strncpy(test, "123", 2);
    printf("%s\n", test);
    free(test);
    return 0;
}

Когда я запускаю Valgrind с ---track-origins=yes, я получаю такой вывод:

==91702== Conditional jump or move depends on uninitialised value(s) 
==91702==    at 0x100011507: strlen (mc_replace_strmem.c:282)
==91702==    by 0x1000AA338: puts (in /usr/lib/libSystem.B.dylib)
==91702==    by 0x100000EFA: main (valgrind_test.c:10)
==91702==  Uninitialised value was created by a heap allocation
==91702==    at 0x100010345: malloc (vg_replace_malloc.c:236)
==91702==    by 0x100000EEA: main (valgrind_test.c:8)

Это кажется мне ложным срабатыванием, но яЯ не уверен в своих силах, чтобы списать их со счетов.Может я неправильно распределяю или неправильно использую strncpy?Я не уверен.

Заранее спасибо

Ответы [ 3 ]

18 голосов
/ 14 июня 2011

Нет, это неработающий код.

У вас есть блок памяти с 3 неинициализированными символами.Затем вы копируете "12" в него и не завершаете.Остерегайтесь strncpy().

Я цитирую документацию :

Функция strncpy () похожа, за исключением того, что не более n байтов srcскопировано.Таким образом, если среди первых n байтов src нет нулевого байта, результат не будет нулевым.

Поскольку в первых 2 символах источника нет завершения, назначение не прекращается.

5 голосов
/ 15 июня 2011

Идиоматические способы использования strcpy() и strncpy():

Если вы знаете, что в буфере есть место для строки плюс терминатор NUL, вы можете использовать strcpy(). Это, вероятно, будет использовать константы или иметь проверки в коде (вы должны убедиться, что проверки правильные).

В противном случае вы можете сделать:

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

, который имеет следующие недостатки:

  • может обрезать строки.
  • это потенциально неэффективно, так как оно всегда заполняет length байт.

Существует также OpenBSD strlcpy().

Любое другое использование strcpy()/strncpy() потенциально подозрительно, и вам следует внимательно на них смотреть.

Итог: избегайте строковых функций C для чего-либо достаточно сложного, попробуйте использовать некоторую библиотеку для динамически размещаемых строк. Qmail / Postfix свертываются самостоятельно, GNU имеет препятствий .

1 голос
/ 14 июня 2011

В вашей строке нет терминатора, поэтому, вероятно, valgrind прав, когда жалуется.Изменить:

strncpy(test, "123", 2);

на:

strcpy(test, "12");
...