双重自由问题

sur*_*esh 3 c

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

moo*_*dow 28

不要那样做.

不完全是.解决实际问题.一旦免费()被调用上的指针,你的代码应该被抓着它的任何理由.把它弄清楚所以你不能再把它释放出来; 这将使由过时指针解除引用引起的任何其他问题也可见.

  • @Chris:是什么让你认为`free(NULL)`会抛出错误?ANSI标准,第4.10.3.2节:"如果ptr是空指针,则不会发生任何操作." (9认同)
  • +1用于将指针设置为NULL.这实际上是从来没有双重免费的最简单的解决方案.无论如何,编写自定义`my_free()`执行`free()`然后将指针设置为NULL似乎是确保这一点的最简单方法.但这涉及代码更改:-) (6认同)
  • 如果你有两个相同指针的副本,那么通过free()或free()的包装器将一个设置为null将不会阻止尝试释放第二个副本. (4认同)

pmg*_*pmg 8

不要那样做

一种简单的方法是定义你的包装函数和#define free来代替调用你的函数.

#undef free
#define free(x) wrapper_free(x)
/* ... */
int *data = malloc(42);
free(data); /* effectively calls wrapper_free(data) */
Run Code Online (Sandbox Code Playgroud)

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

  • 你应该在你的defenition之前做一个`#undef free`:C标准允许stdlib函数作为宏实现 (2认同)

Chr*_*oph 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
Run Code Online (Sandbox Code Playgroud)

来源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);
}
Run Code Online (Sandbox Code Playgroud)