设置条件以避免双重释放已分配的内存

时间:2010-11-23 03:45:49

标签: c malloc free

Ubuntu 10.10 gcc 4.4.4

我正在尝试分配和释放。

但是,当一个对象被多次释放时,我试图避免这个问题。

但是,当我测试时,我注意到创建和释放的obj没有返回到null状态。那么我可以设置哪些条件可以避免这种情况发生吗?

我也试过在free之后将对象设置为NULL。但是,它仍然试图释放该对象。

这是对这个问题的引用,只是因为你知道不是重复的: freeing allocated memory

我的代码如下:

#include <stdio.h>
#include "objects.h"

int main(void)
{
    obj_t *obj = NULL;

    obj = create_object();

    destroy_object(obj);

    destroy_object(obj);

    return 0;
}

==

#ifndef OBJECTS_H_INCLUDED
#define OBJECTS_H_INCLUDED

typedef struct Obj_t obj_t;

obj_t* create_object();
void destroy_object(obj_t *obj);

#endif /* OBJECTS_H_INCLUDED */

==

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

#include "objects.h"

struct Obj_t {
    int obj_id;
};

obj_t* create_object()
{
    obj_t *obj = malloc(sizeof obj);

    return obj;
}

void destroy_object(obj_t *obj)
{
    if(obj != NULL) {
        printf("Object [ %d ] will be deleted\n", obj->obj_id);
        free(obj);
    }
}

==

OBJECT_FILES = objects.o main.o
CFLAGS = -Wall -Wextra -Wunreachable-code -ggdb -O0
CC = gcc
TARGET = obj

$(TARGET): $(OBJECT_FILES)
    $(CC) $(CFLAGS) $(OBJECT_FILES) -o $(TARGET)

main.o: main.c objects.c
    $(CC) $(CFLAGS) -c main.c

objects.o: objects.c
    $(CC) $(CFLAGS) -c objects.c 

clean:
    rm -f $(OBJECT_FILES) $(TARGET) *~

6 个答案:

答案 0 :(得分:5)

问题是Main中指针的值永远不会更新,因为您将指针的副本传递给destroy_object。你需要的是指向指针的指针。试试这个:

void destroy_object(obj_t **obj)
{
    if(*obj != NULL) {
        printf("Object [ %d ] will be deleted\n", *obj->obj_id);
        free(*obj);
        *obj = NULL;
    }
}

然后:

destroy_object(&obj);

答案 1 :(得分:4)

你不能在destroy_object函数中将指针设置为NULL,因为函数内部指针的值是指针的 copy

在C和C ++中,程序员如何避免两次释放或删除对象不能

如果您发现自己编写的程序无法判断对象有多少引用,那么首先要做的是重新考虑您的设计。

然后,如果你真的必须,使用C ++ shared_ptr,或在C中实现自己的引用计数方案.Perl和Python都在它们的C实现中这样做。

答案 2 :(得分:2)

正如其他人所说,在obj内设置NULLdestroy_object()正在更改本地变量,并且在main()中无效。

但是,如果您希望让destroy_object()尝试警告程序员关于双重释放,作为调试辅助,那么您可以使用 poison 值的概念。在您的示例中,您可能会保留一些特定的无效obj_id值来表示“已经释放” - 例如-1。您的destroy_object()功能将如下所示:

#define OBJ_POISON (-1)

void destroy_object(obj_t *obj)
{
    if (obj != NULL) {
        if (obj->obj_id == OBJ_POISON) {
            fprintf(stderr, "Double-free of object @ %p detected, aborting.\n", obj);
            abort();
        }

        printf("Object [ %d @ %p ] will be deleted\n", obj->obj_id, obj);
        obj->obj_id = OBJ_POISON; 
        free(obj);
    }
}

(当然,为了实现这一点,您的create_object()函数还必须将obj_id设置为有效值,例如0)。

请注意,这并不是为了让双重释放“正常工作” - 它只是为了让它在调试时更加醒目。

答案 3 :(得分:1)

通常,对象只有一个有权删除它的所有者是一个好习惯。在同一时间,您可以保留一个指向该对象的单个指针,并确保在删除对象后将该指针设置为NULL。或者,总有标准的C ++解决方案:智能指针。

答案 4 :(得分:0)

这不是一个全新的想法,因此您可能希望了解Reference CountingSmart Pointers

Standard Template Library (STL)Boost都大量使用这些概念。

答案 5 :(得分:0)

Objective-C执行reference counting,一旦引用计数达到零,就释放一个对象。您还可以查看smart pointers