Подтвердить что ты не робот

Valgrind - Адрес ---- - 0 байт после блока размера 8 alloc'd

Во-первых, я знаю, что подобные вопросы были заданы. Тем не менее, я хотел бы иметь более общий простой вопрос с действительно примитивными типами данных C. Итак, вот оно.

В main.c Я вызываю функцию для заполнения этой строки:

int
main (int argc, char *argv[]){

    char *host = NULL ;
    char *database ;
    char *collection_name;
    char *filename = ""; 
    char *fields = NULL;
    char *query = NULL;
    ...

    get_options(argc, argv, &host, &database, &collection_name, &filename, 
                &fields, &query, &aggregation);

Внутри get_options:

if (*filename == NULL ) {
   *filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+4);
    strcpy(*filename, *collection_name);
    strcat(*filename, ".tde");  # line 69 
}

Моя программа работает нормально, но тогда Valgrind говорит мне, что я делаю это неправильно:

==8608== Memcheck, a memory error detector
==8608== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==8608== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==8608== Command: ./coll2tde -h localhost -d test -c test
==8608== 
==8608== Invalid write of size 1
==8608==    at 0x403BE2: get_options (coll2tde.c:69)
==8608==    by 0x402213: main (coll2tde.c:92)
==8608==  Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd
==8608==    at 0x4C28BED: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x4C28D6F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==8608==    by 0x403BBC: get_options (coll2tde.c:67)
==8608==    by 0x402213: main (coll2tde.c:92)

Вы можете объяснить ошибку Address 0xa2edd18 is 0 bytes after a block of size 8 alloc'd? Как я могу решить эту проблему?

4b9b3361

Ответ 1

strcpy добавляет символ нулевого ограничителя '\0'. Вы забыли выделить для этого место:

*filename = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);

Вам нужно добавить пробел для 5 символов: 4 для суффикса ".tde" и еще один для терминатора '\0'. Ваш текущий код выделяет только 4, поэтому последняя запись выполняется в пространстве сразу после блока, который вы выделили для нового имени файла (т.е. 0 байтов после него).

Примечание. У вашего кода есть общая проблема - он присваивает результаты realloc непосредственно перераспределяемому указателю. Это нормально, когда realloc успешно, но создает утечку памяти, когда он терпит неудачу. Для исправления этой ошибки необходимо сохранить результат realloc в отдельной переменной и проверить его на NULL, прежде чем присвоить значение *filename:

char *tmp = (char*)realloc(*filename, strlen(*collection_name)*sizeof(char)+5);
if (tmp != NULL) {
    *filename = tmp;
} else {
    // Do something about the failed allocation
}

Присвоение непосредственно *filename создает утечку памяти, поскольку указатель *filename указывал ниже, стал бы перезаписанным при сбое, становясь невосстановимым.