双重自由问题

时间:2009-09-17 14:27:23

标签: c

如何通过编写一个名为free的包装函数来解决双重免费问题,这样我就不需要在源代码中更改每个免费调用了?

6 个答案:

答案 0 :(得分:28)

不要那样做。

不,真的。解决实际问题。一旦在指针上调用了free(),你的代码应该以任何理由持有它。把它弄清楚所以你不能再把它释放出来;这将使陈旧指针解除引用引起的任何其他问题也可见。

答案 1 :(得分:8)

不要那样做

一种简单的方法是定义你的包装函数,然后#define free来调用你的函数。

#undef free
#define free(x) wrapper_free(x)
/* ... */
int *data = malloc(42);
free(data); /* effectively calls wrapper_free(data) */

但...... 不要那样做!

答案 2 :(得分:7)

以下代码拦截了对malloc()realloc()calloc()的调用以进行日志记录。

当调用free()时,它会检查内存是否先前已分配了其中一个函数。如果没有,该程序将被终止。将报告释放空指针,但将继续执行。

标题memdebug.h

#undef free
#define free(PTR) memdebug_free(PTR, #PTR, __FILE__, __func__, __LINE__)

#undef malloc
#define malloc(SIZE) memdebug_log(malloc(SIZE))

#undef realloc
#define realloc(PTR, SIZE) memdebug_log(realloc(PTR, SIZE))

#undef calloc
#define calloc(COUNT, SIZE) memdebug_log(calloc(COUNT, SIZE))

#ifndef MEMDEBUG_H
#define MEMDEBUG_H

extern void memdebug_free(void *ptr, const char *ptr_arg, const char *file, 
    const char *func, int line);
extern void *memdebug_log(void *ptr);

#endif

来源memdebug.c

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#ifndef MEMDEBUG_TABLE_SIZE
// log 16k allocations by default
#define MEMDEBUG_TABLE_SIZE 0x4000
#endif

static void *alloc_table[MEMDEBUG_TABLE_SIZE];
static size_t top;

void *memdebug_log(void *ptr)
{
    assert(top < sizeof alloc_table / sizeof *alloc_table);
    alloc_table[top++] = ptr;
    return ptr;
}

void memdebug_free(void *ptr, const char *ptr_arg, const char *file,
    const char *func, int line)
{
    if(!ptr)
    {
        fprintf(stderr,
            "%s() in %s, line %i: freeing null pointer `%s` -->continue\n",
            func, file, line, ptr_arg);

        return;
    }

    for(size_t i = top; i--; )
    {
        if(ptr == alloc_table[i])
        {
            free(ptr);
            --top;
            if(i != top) alloc_table[i] = alloc_table[top];
            return;
        }
    }

    fprintf(stderr,
        "%s() in %s, line %i: freeing invalid pointer `%s`-->exit\n",
        func, file, line, ptr_arg);

    exit(EXIT_FAILURE);
}

答案 3 :(得分:1)

我同意其他帖子说你不应该这样做。主要是,让某人查看你的代码并试图找出正在发生的事情(当他们习惯于看到免费只释放内存时)会更加令人困惑。

如果您正在寻找允许您释放和清除指针的单行代码,我建议使用宏,尽管还有其他方法可以执行此操作(创建一个带指针的方法到你的指针)。

#define FREEANDCLEAR(pointer)\
{\
   free(pointer);\
   pointer = 0;\
}

修改 正如Christoph在评论中提到的那样,您还可以确保用户像使用函数一样使用宏(通过使用do来结束使用分号的行:

#define FREEANDCLEAR(pointer)\
do {\
   free(pointer);\
   pointer = 0;\
} while(0)

将执行一次并需要一个结束分号。

答案 4 :(得分:1)

除了所有其他答案和对内存管理开发的参考等。

当发生双重自由时,代码中会出现错误,表明事情没有按照正确的顺序进行,等等。

大约10年前,当我开始使用Java时,每个人都称赞Java,因为你不必为新/删除而烦恼。

我很烦恼(因为我习惯用C / C ++开发),因为突然所有开放/关闭,创建/破坏,锁定/解锁模式除了malloc / free之外在软件中以多种方式出现因为每个人都相信所有的清理都是自动的,所以要打破。

因此,当您遇到这些问题时,您可能迟早会遇到其他问题。资源占用,数据库连接被消耗,文件锁定在文件系统上。

Double free是一个信号,表明你的程序没有一个好的结构,例如,在一个层中分配并在另一个层中释放的东西。

答案 5 :(得分:0)

查看stackoverflow问题的答案,"Write your own memory manager"

使用这些答案中的工具或技术,您可以使用内存管理器来检查这些类型的问题,以便您可以识别并修复它们(正如许多其他问题的答案所示,使用某些东西不是一个好主意)像这样作为解决方法)。