【问题标题】:Heap corruption when freeing allocated memory (C)释放分配的内存时堆损坏 (C)
【发布时间】:2012-07-27 00:38:19
【问题描述】:

我正在动态分配内存以维护项目列表,但在尝试使用 free() 删除项目时,我收到内存堆损坏错误。而且我知道这在 C++(或 java,或任何其他面向对象的语言)中会容易得多,但我必须在 C 中执行此操作(注意:C 代码,但在 Microsoft Visual Studio 2010 中编译,并且因此是 C++ 编译器)。

这是项目“看起来”的样子:

//item.h
typedef struct 
{
    char* titel;
    char* auteur;
    int jaar;
} Boek;

typedef struct
{
enum {BOEK, TIJDSCHRIFT} itemType;
    union {
        Boek* boek;
        Tijdschrift* tijdschrift;
    } itemData;
    struct Item* next;
} Item;

这是它的创建/分配方式。我还在使用strdupmalloc/strcpy 来分配字符串之间切换,但这似乎没有任何效果。此外,我要删除的项目是 BOEK 类型,TIJDSCHRIFT allocator/deallocator 以类似的方式工作。

//item.c
Item* nieuwBoek(char* _titel, char* _auteur, int _jaar)
{
    Item* item = (Item*) malloc(sizeof(Item*));
    item->itemType=BOEK;
    item->itemData.boek=(Boek*) malloc(sizeof(Boek*));
    item->itemData.boek->titel=strdup(_titel);
    item->itemData.boek->auteur=strdup(_auteur);
    item->itemData.boek->jaar=_jaar;
    item->next=NULL;
    return item;
}

返回的指针随后被另一个函数使用,该函数将其传递给列表中前一项的item->next

这是我试图释放它的方法。我的理解是我必须在释放结构本身之前释放分配的字符串,但即使我只是调用 free(item) (通过注释掉 deleteItem 中的其他代码或在主代码中调用它:free(nieuwBoek(...) 我收到堆损坏错误。

void deleteItem(Item* item)
{
    if (item->itemType==BOEK)
    {
        free(item->itemData.boek->titel); // When not running in debug-mode it crashes here.
        free(item->itemData.boek->auteur);
        free(item->itemData.boek); // When running in debug mode it crashes here.
    }
    /*else if... TIJDSCHRIFT deallocator here*/
    free(item); 
}

并且传递给deleteItem() 的指针是指向一个项目的有效指针。它可能是我做错/失踪的一些非常愚蠢的事情,但我现在整天都被这个问题难住了,所以我向你们寻求帮助。哦,在删除项目之前,next->pointer 已设置为 NULL,因此它已经与列表断开连接,如果这很重要的话。

【问题讨论】:

  • malloc(sizeof(Boek*)); 应该是 sizeof *boeksizeof(Boek)(对于 item en tijdschrift 类似)verder:1)不要转换 malloc() 的返回值。 2) 不要使用带有前导下划线的标识符;它们是为实现而保留的。
  • 问题是你的 malloc 的:malloc(sizeof(Item*))。他们应该是malloc(sizeof(Item)); 等等...
  • sizeof(Item*) 是指针的大小,而不是项目的大小....很少计划采取指针大小的操作!

标签: c pointers malloc free heap-corruption


【解决方案1】:
Item* item = (Item*) malloc(sizeof(Item*));

您应该将 sizeof 更改为 sizeof(Item)sizeof(*item)。否则,您将只分配足够的空间来容纳一个指针,而对于您的结构来说还不够。

我个人更喜欢sizeof *item - 这样如果我改变它的类型,我只需要在一个地方做。


旁注:

  • 损坏意味着什么:由于您分配的内存很少,当 您填写了结构字段以弄乱内部簿记 malloc 和下一个操作检测到它
  • 虽然是个人喜好问题,但您可能不应该返回malloc

【讨论】:

  • 我想大多数人会更喜欢sizeof(Item)。不管怎样,你是对的:)
  • 谢谢,成功了。老实说,我不知道为什么我把那个*放在那里,当我写那部分时我一定很累。一直以来,它一直盯着我的脸。关于 malloc 的返回,我读到最好不要这样做,但是我们在 CS 课中的 C 教科书在示例代码中总是这样做的。因此,从不想承担风险损失点超过技术的角度来看,我只是继续这样做。
【解决方案2】:

这个:

Item* item = (Item*) malloc(sizeof(Item*));

只为一个指针分配足够的空间。您想为整个 Item 结构分配足够的空间:

Item* item = (Item*) malloc(sizeof(Item));

同样的这个分配:

item->itemData.boek=(Boek*) malloc(sizeof(Boek*));

应该是:

item->itemData.boek=(Boek*) malloc(sizeof(Boek));

【讨论】:

    【解决方案3】:

    晚会发帖,但 Valgrind 检测到此类问题。我遇到了这个问题,这让我发疯了,因为 GCC 会允许程序运行,但 VC2012 每次都会崩溃。 Valgrind 展示了以下内容:

    大小为 8 的无效写入 在 0x10CC33: appendListItem (structMgmt.c:170) 由 0x10BB6E: 解析 (parse.c:304) 由 0x10A790:runParsingTests (CTSLicense.c:562) 通过 0x109B7F: 主要 (CTSLicense.c:41) 地址 0x5207748 是一个大小为 8 的块分配后的 0 个字节 在 0x4C2CB3F:malloc(在 /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so 中) 由 0x10CC2A: appendListItem (structMgmt.c:169) 由 0x10BB6E: 解析 (parse.c:304) 由 0x10A790:runParsingTests (CTSLicense.c:562) 通过 0x109B7F: 主要 (CTSLicense.c:41)

    这非常令人困惑(我已经知道 C 2 周了)。我不小心为指针而不是结构使用了 malloc。现在我的程序在 GCC 和 VC2012 中运行没有任何问题。

    使用 Microsoft 的 pageheap 检测工具对查找问题的根本原因没有多大帮助。它确实告诉我存在堆损坏而不是出现的其他愚蠢错误,但不是问题的根源。

    Microsoft's heap detection tool

    Hints to using valgrind to find this problem

    【讨论】:

      猜你喜欢
      • 2012-06-28
      • 2011-08-21
      • 2021-08-14
      • 2017-05-22
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 2019-09-23
      • 2020-10-02
      相关资源
      最近更新 更多