Search code examples
cpointersmemory-managementdynamic-memory-allocation

Is there a way to set all the pointers pointing to the freed memory to NULL?


I want to set all the pointers pointing to a freed memory location to NULL, so that no dangling pointers or double frees are possible. Is this possible in C?

For example, I have the following structures:

struct B {
    int *arr;
    unsigned int len;
};

struct A {
    struct B *b;
};

// Freeing and setting them to NULL:
bool test_safe_free() {
    struct A *a = malloc(sizeof(struct A));
    struct B *b = malloc(sizeof(struct B));
    b->arr = malloc(100 * sizeof(int));
    b->len = 100;
    a->b = b;

    safe_free_A(&a);
    return a == NULL && b == NULL;
}

void safe_free_B(struct B **b_ref) {
    if (*b_ref != NULL) free((*b_ref)->arr);
    (*b_ref)->arr = NULL;
    free(*b_ref);
    *b_ref = NULL;
}

void safe_free_A(struct A **a_ref) {
    // Before freeing A, freeing B:
    if (*a_ref != NULL) safe_free_B(&((*a_ref)->b));
    free(*a_ref);
    *a_ref = NULL;
}

The test_safe_free function returns false, because even though the variable a is set to NULL after freeing, b is still pointing the freed memory, because the pointer is copied (and the copy is set to NULL, while the original remains the same) when a passed into the function.

I couldn't come up with a way, a structure to resolve this, but I'm also not sure whether what I'm trying to do is even possible.


Solution

  • The C language doesn't keep track of all the copies you make of a pointer variable.

    C++ can do this with the concept of smart pointers, however C can't because it doesn't have functionality similar to a destructor. It's up to the programmer to keep track of any references and manage them appropriately.

    One way to do this is to implement reference counting, which is not a trivial undertaking. You would need to create a structure that would act as a header for all allocated memory segments that holds the current reference count. You would then need to create a wrapper for malloc and family that allocates space for the header plus the requested space, write to the header at the start of the memory block, then return a pointer to the memory just after the block. You then need a function that can increase the reference count that you call manually when you make a new reference. Then you need a function to decrease the reference count which would call free when it hits 0.

    Of course, even if you do this, you trade knowing when not to call free with remembering to increase/decrease the reference count where necessary. A failure to increment means using freed memory and/or a double free, while a failure to decrement means a memory leak.