Valgrind + C: обработка неинициализированных указателей без ошибок - PullRequest
0 голосов
/ 15 февраля 2020

Возможно, я слишком увлекся тестированием своего задания, но вот моя дилемма:

Это моя оскорбительная функция (более или менее):

struct thing{
    char* data;
}

int function(struct thing* arg){
    if(arg->data == NULL)
        return -1; 
}

Это мой оскорбительный ввод:

struct thing *x = malloc(sizeof(struct thing));
function(x);

И valgrind выводит это, когда я проверяю это:

Conditional jump or move depends on uninitialised value(s)

Я примерно на 99% уверен, что это потому, что у valgrind есть проблема с оценкой x->data, когда у него нет не было инициализировано на NULL или неправильно. Есть ли обходной путь для этого?

Ответы [ 3 ]

5 голосов
/ 15 февраля 2020

На мой взгляд, valgrind прав, когда жалуется здесь, потому что data на самом деле не инициализирован и function не может определить, так ли это. Функция может только проверить, имеет ли она определенное значение, которое вы использовали для инициализации.

Так что я бы рассмотрел использование функции создания, которая также выполняет инициализацию. Таким образом, вы также можете сразу выделить память для данных при передаче их размера в качестве параметра (или просто NULL, если вы хотите сделать это позже).

struct thing *newThing(size_t dataSize)
{
   struct thing *t = malloc(sizeof (struct thing));

   if (t)
      t->data = malloc(sizeof(char) * dataSize);
      // or t->data = NULL if it should be done later

   return t;
}
2 голосов
/ 15 февраля 2020

Вы определяете функцию следующим образом:

int function(struct thing *arg) {
    if (arg->data == NULL) {
        // abort here
        return 1;
    } else {
        // use the value here
        return 0;
    }
}

Здесь Вальгринд прав, когда жалуется, потому что невозможно достичь предполагаемого поведения для function(). Если arg->data не инициализируется явно, его значение является неопределенным, и оператор if может выполнить любую из двух ветвей в зависимости от того, какое случайное значение он читает из arg->data.

В общем случае функция не может работать правильно, потому что:

  1. Если проверка arg->data == NULL не пройдена, остальная часть кода будет предполагать, что arg->data не NULL и поэтому используйте недопустимое значение, что, скорее всего, вызовет cra sh или другие проблемы.
  2. Если проверка arg->data == NULL пройдена, остальная часть кода ошибочно предположит, что data известно, что является недействительным , и делает любые другие вещи, предполагая, что data должен был быть NULL, например, вызывает некоторый код очистки в неподходящее время.

Кроме этого, если вы действительно хотите быть педантичным c, чтение неинициализированных переменных на самом деле неопределенное поведение в C.

Правильный выбор в вашем случае либо используйте calloc() вместо malloc() или для ручной установки x->data = NULL сразу после malloc().

1 голос
/ 15 февраля 2020

Память, выделенная для mallo c, не инициализирована.

Вам необходимо установить ее в состояние знания:

struct thing *x = calloc(1,sizeof(*x));

или

struct thing *x = malloc(sizeof(*x));
memset(x, 0, sizeof(*x);

Вы также можете, конечно, просто присвоить некоторые значения членам структуры,

struct thing *x = malloc(sizeof(*x));
x -> data = NULL;
...