Утечка памяти и ошибки valgrind в этом маленьком цикле for?

У меня проблемы с этой небольшой частью кода, которая генерирует ошибки в valgrind. Когда я комментирую код и запускаю valgrind, я не получаю никаких утечек памяти или ошибок, поэтому причиной должен быть этот цикл:

///Print the top users
    const char* str;
    for (int i = 0; i < count; i++) {
        if (FinalArray[i].Score == -1) {
            break;
        }

        int id = UserGetID(user);
        char* name = UserGetName(user);
        int finalID = UserGetID(FinalArray[i].user);
        char* finalName = UserGetName(FinalArray[i].user);

        assert(finalName!= NULL && name !=NULL);
        str = mtmSuggestFriends(id, name, finalID, finalName);

        if (str == NULL) {
            return MAIN_ALLOCATION_FAILED;
        }

//      fprintf(fileOutput, str);
    }

после этого цикла я просто возвращаю перечисление, сообщающее об успехе.

Вот ошибки в Valgrind:

==8779== Use of uninitialised value of size 8
==8779==    at 0x4037C2: UserGetName (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FAC: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== Use of uninitialised value of size 8
==8779==    at 0x4037A0: UserGetID (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FC8: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== Invalid read of size 1
==8779==    at 0x403F1A: mtmSuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FEE: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==  Address 0x9848B4458BB44589 is not stack'd, malloc'd or (recently) free'd
==8779== 
==8779== Process terminating with default action of signal 11 (SIGSEGV)
==8779==  General Protection Fault
==8779==    at 0x403F1A: mtmSuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FEE: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 1)
==8779== malloc/free: in use at exit: 1,250 bytes in 93 blocks.
==8779== malloc/free: 455 allocs, 362 frees, 10,081 bytes allocated.
==8779== For counts of detected errors, rerun with: -v
==8779== searching for pointers to 93 not-freed blocks.
==8779== checked 122,512 bytes.
==8779== 
==8779== LEAK SUMMARY:
==8779==    definitely lost: 0 bytes in 0 blocks.
==8779==      possibly lost: 0 bytes in 0 blocks.
==8779==    still reachable: 1,250 bytes in 93 blocks.
==8779==         suppressed: 0 bytes in 0 blocks.
==8779== Reachable blocks (those to which a pointer was found) are not shown.
==8779== To see them, rerun with: --show-reachable=yes

Функция ToStringUser возвращает malloc из const char*.. Так что мне не стоит беспокоиться об ее освобождении, верно?

Любая идея, почему это происходит?

Я попытался освободить str с помощью этого кода в for, но я продолжаю получать те же ошибки и такое же количество утечек памяти:

free((char*) str); OR free((void*) str);

Вот структура пользователя, getID и getName:

struct User_t {
    char *Name;
    int ID;
    int Birth;
};
int UserGetID(User user) {
    return user->ID;
}
char* UserGetName(User user) {
    return user->Name;
}

Перед циклом я инициализирую нового пользователя следующим образом:

User user = FindUserPointer(setUser, id);

Используется следующая функция:

static User FindUserPointer(Set users, int ID) {
        assert(users!=NULL);
    User tmpUser = UserCreate("temp", ID, 99);
    if (tmpUser == NULL) {
        return NULL;
    }
    SET_FOREACH(User,Itrator1,users) {
        if (UserCompare(tmpUser, Itrator1) == 0) {
            UserFree(tmpUser);
            return Itrator1;
        }
    }
    UserFree(tmpUser);
    return NULL;
}

person Omar    schedule 04.05.2012    source источник
comment
почему бы тебе не побеспокоиться об освобождении его?   -  person msam    schedule 04.05.2012
comment
Вы всегда должны беспокоиться об освобождении памяти.   -  person Philip    schedule 04.05.2012
comment
Что такое user в цикле for? И программа segfaults в функции mtmSuggestFriends, так что может быть полезно это увидеть.   -  person huon    schedule 04.05.2012
comment
@msam, даже если я освобожу его, приведя str к void* или char*, я продолжаю получать эти ошибки и 93-й блок утечки памяти.   -  person Omar    schedule 04.05.2012
comment
@dbaupp Я создаю пользователя и получаю указатель на этого пользователя в начале этой функции (до цикла): User user = FindUserPointer(setUser, id);. Что касается mtmSuggestFriends, он находится в объектном файле, и у меня нет кода, хотя он не должен быть причиной проблемы, потому что у моих друзей не было проблем с его использованием.   -  person Omar    schedule 04.05.2012
comment
@Philip Как мне освободить константу ..? Даже когда я освобождаю str с приведением, я получаю ошибки и утечки памяти. Вопрос обновлен   -  person Omar    schedule 04.05.2012
comment
@ Омар, программа дала сбой. Ваша утечка - еще одна проблема.   -  person IanNorton    schedule 04.05.2012
comment
@Omar: Вызвав для него free() ;) Обратите внимание, что free() не меняет значение своего аргумента, хотя в любом случае это не имеет значения.   -  person Philip    schedule 04.05.2012
comment
@Philip Я получаю эту ошибку при освобождении str без приведения: передача аргумента 1 «free» отбрасывает квалификатор «const» из целевого типа указателя.   -  person Omar    schedule 04.05.2012
comment
@ Омар, программа вылетает (вот что означают Invalid read of size 1 + SIGSEGV), вы должны исправить это, прежде чем слишком беспокоиться о free использовании памяти.   -  person huon    schedule 04.05.2012
comment
@ Омар: Ты прав. Я просмотрел его, и идиоматическое решение состоит в том, чтобы не использовать указатели const для хранения результата malloc(). В любом случае это не имеет смысла, поскольку впоследствии вы собираетесь изменить (например, free()) указатель.   -  person Philip    schedule 04.05.2012
comment
@Philip Проблема была в другом. Я выходил за пределы массива. когда я это исправил, у меня не было ни ошибок, ни утечек памяти. Мне не нужно освобождать константу. Я думаю, она освобождается автоматически :). Спасибо за помощь вам и всем остальным!   -  person Omar    schedule 04.05.2012


Ответы (3)


Valgrind не жалуется на утечку — он жалуется, что вы читаете неинициализированную память и разыменовываете недопустимый указатель (deref недопустимого указателя приводит к сбою программы — по крайней мере, в Valgrind).

Нам нужно увидеть UserGetID() и UserGetName(), чтобы иметь надежду определить ошибку в них (но этого может быть недостаточно).

Основываясь на вашем комментарии о том, что mtmSuggestFriends является объектным файлом, для которого у вас нет исходного кода, я предполагаю, что UsetGetID() и/или UserGetName() передают недопустимые указатели на mtmSuggestFriends.

person Michael Burr    schedule 04.05.2012
comment
Вопрос обновлен с кодом. mtmSuggestFriends — это функция в объектном файле. он вычисляет и возвращает const char*. Это не причина утечки, так как многие из моих друзей использовали его, и при его использовании утечек не было. - person Omar; 04.05.2012
comment
Я обновил цикл for с утверждениями (см. код выше), и он все еще работает. - person Omar; 04.05.2012
comment
Теперь мы знаем больше, но не знаем, как выглядят данные, переданные в FindUserPointer(), или что такое SET_FOREACH(). Но, судя по вашему описанию mtmSuggestFriends, проблема может заключаться в том, что куча повреждена. Возможно, в UserCreate() есть ошибка (может быть, недостаточно памяти, чтобы включить нулевой терминатор в строку Name?). - person Michael Burr; 04.05.2012
comment
@Omar: пройдите цикл в отладчике. Бьюсь об заклад, в какой-то момент name окажется не NULL, но укажет на бессмысленную/недействительную память. Это все равно пройдет assert(), но не сделает mtmSuggestFriends() счастливым. - person Michael Burr; 04.05.2012
comment
Я сделал это и обнаружил, что полученный нами тест требовал больше пользователей, чем у меня было на самом деле, поэтому мне пришлось проверить полученное число user_count на максимальное число, которое я мог напечатать (и не больше). Итак, я выходил из FinalArray границы. Я добавил небольшой if(..), и теперь у меня нет ни утечек памяти, ни ошибок. Спасибо за помощь, Майкл. - person Omar; 04.05.2012

Во-первых, вы передаете неназначенный указатель user. Затем ваша функция SuggestFriends(), вызванная из UserGetID(), использует этот указатель мусора, полный случайности, в качестве реального указателя, что приводит к недопустимому чтению (SEGV)

Вы можете обнаружить, что установка «предупреждений как ошибок» (-Werr в gcc), вероятно, покажет вам, где вы делаете непредсказуемые вещи.

person IanNorton    schedule 04.05.2012
comment
Я обновил код с назначением пользователя. Я отладил код с помощью eclipse, и пользователь не является NULL при достижении этой ошибки. - person Omar; 04.05.2012
comment
точно, это не NULL, это значение, которое не является допустимым указателем, вероятно, откуда valgrind жалуется на использование неинициализированной переменной. Вы должны ВСЕГДА инициализировать указатели на NULL. - person IanNorton; 04.05.2012
comment
Я пробовал так: User user = NULL; пользователь = FindUserPointer (setUser, id); Это то, что ты имеешь в виду? Я все еще получаю ту же ошибку. Я также пытался вернуть КОПИЮ пользователя в FindUserPointer, но все равно smae. - person Omar; 04.05.2012

struct User_t {
char *Name;
int ID;
int Birth;
};
int UserGetID(User user) {
    return user->ID;
}

... и где определяется User?

person msam    schedule 04.05.2012