【问题标题】:Memory leak and valgrind errors in this small for loop?这个小的 for 循环中的内存泄漏和 valgrind 错误?
【发布时间】:2012-05-13 17:12:50
【问题描述】:

我在处理 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 返回一个 const char* 的 malloc.. 所以我不应该担心释放它对吗?

知道为什么会这样吗?

我尝试在 for 中使用此代码释放 str,但我不断收到相同的错误和相同数量的内存泄漏:

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

这是 User 的结构体以及 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;
}

【问题讨论】:

  • 你为什么不担心释放它?
  • 你应该总是担心释放内存。
  • for 循环中的user 是什么?并且mtmSuggestFriends 函数中的程序段错误,因此查看它可能很有用。
  • @msam 即使我通过将 str 强制转换为 void* 或 char* 来释放它,我也会不断收到这些错误和 93 块内存泄漏。
  • @Omar,程序崩溃了。您的泄漏是另一个问题。

标签: c memory-leaks valgrind


【解决方案1】:
struct User_t {
char *Name;
int ID;
int Birth;
};
int UserGetID(User user) {
    return user->ID;
}

...User 定义在哪里?

【讨论】:

    【解决方案2】:

    Valgrind 没有抱怨泄漏 - 它抱怨您正在读取未初始化的内存并取消引用无效指针(无效指针 deref 导致程序崩溃 - 至少在 Valgrind 下)。

    我们需要查看UserGetID()UserGetName() 才能确定其中的错误(但这可能还不够)。

    根据您的评论,mtmSuggestFriends 是一个您没有源文件的目标文件,我猜UsetGetID() 和/或UserGetName() 将无效指针传递给mtmSuggestFriends

    【讨论】:

    • 用代码更新的问题。 mtmSuggestFriends 是目标文件中的一个函数。它 malloc 并返回一个 const char*。它不是泄漏的原因,因为我的许多朋友都使用它并且使用它时有 0 个泄漏。
    • 我用断言更新了 for 循环(参见上面的代码),它仍然有效。
    • 现在我们知道的更多,但不知道传递给FindUserPointer() 的数据是什么样的,或者SET_FOREACH() 是什么。但是根据您对mtmSuggestFriends 的描述,问题可能是堆已损坏。也许UserCreate() 有一个错误(可能没有分配足够的内存来包含Name 字符串上的空终止符?)。
    • @Omar:在调试器中单步执行循环。我敢打赌name 最终会是非NULL,但指向无意义/无效的内存。这仍然会通过assert(),但不会让mtmSuggestFriends() 开心。
    • 我这样做了,我发现我们得到的测试需要的用户比我实际拥有的更多,所以我必须检查收到的 user_count 是否达到我可以打印的最大数量(而不是更多)..所以我要超出 FinalArray 的范围。我添加了一个小的 if(..),现在我没有内存泄漏和错误。感谢 Michael 的帮助。
    【解决方案3】:

    首先,您传入了一个未分配的指针user。然后你从UserGetID()调用的SuggestFriends()函数正在使用这个充满随机性的垃圾指针作为导致无效读取的真实指针(SEGV

    您可能会发现将“警告设置为错误”(gcc 上的-Werr)可能会告诉您您在哪里做不可预测的事情。

    【讨论】:

    • 我用用户分配更新了代码。我用eclipse调试了代码,遇到这个错误时用户不是NULL。
    • 确切地说,它不是 NULL,它是一个不是有效指针的值,可能是 valgrind 抱怨使用未初始化变量的地方。您应该始终将指针初始化为 NULL。
    • 我试过这个:User user = NULL;用户= FindUserPointer(setUser, id);这是你的意思吗?我仍然得到同样的错误。我还尝试在 FindUserPointer 中返回用户的副本,但仍然是 smae。
    猜你喜欢
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 2012-01-27
    • 2022-08-14
    • 2011-07-08
    • 1970-01-01
    相关资源
    最近更新 更多