1
int *a = malloc(40);
int *b;
b=a;
if( *some conditions* )
free(a);
// I know that 'a' has been allocated this chunk of memory X times
// and free(a) has been called less than X times.

I have no idea of that condition, so don't know whether 'a' has been freed or not! So now how would I be sure if 'b' i.e. 'a' has been freed or not.

Maverick33
  • 337
  • 3
  • 15
  • 5
    "I have no idea of that condition, so don't know whether 'a' has been freed or not!" In that case, you're hosed. You can guess of course, half the time you'll guess right. You must keep track of which memory you need to free, and which you mustn't free. If you don't, leaks are the best you can hope for. – Daniel Fischer May 10 '13 at 06:58
  • 1
    _"I know that [...] free(a) has been called less than X times."_ please tell us exactly what you know. – moooeeeep May 10 '13 at 07:02
  • I think the title is too short. –  May 10 '13 at 08:07
  • 3
    Whenever you're dealing with dynamically allocated objects, there has to be a policy about ownership of those objects. Only the owner can free the object, and ownership can be transferred (when that happens is a policy/design decision). There isn't any single answer to how to handle that ownership policy in C. Reference counting is one option; just documenting when passing/returning a pointer to/from something also transfers ownership is another. But as a programmer, you need to know which pointer owns the object and when that ownership is transferred. – Michael Burr May 10 '13 at 08:16
  • @MichaelBurr I think you should put that as an answer. – moooeeeep May 10 '13 at 08:20

4 Answers4

5

If you want to make sure that subsequent calls of free on a pointer to dynamically allocated memory will not do any harm, you should assign NULL to that pointer. Because (emphasis added):

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

If you want to make sure that pointer b will always refer to the same object the other pointer a points at, you could turn b into a pointer to a instead (and dereference it each time you need to use it):

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

int main() {
    /* dynamically allocate some memory */
    int *a = malloc(40);
    /* b is a pointer to a pointer to an int */
    int **b;
    /* make b point to a */
    b = &a;
    if ( 1 ) {
        /* free memory and assign NULL to the pointer */
        free(a);
        a = NULL;
    }
    /* nothing bad will happen when we dereference b now */
    printf("%p\n", *b);
    /* nothing bad will happen when we free the memory region
       where the pointer b points to points to */
    free(*b);
}

Another thing on memory leaks. There will be no memory leaked when you double-free the memory. In that case you will stumble into undefined behavior, in which case anything could happen. Simply because you shall not access memory regions that are not your own (anymore) (c.f., this great post). Instead, you will leak memory when you loose the reference to a block of dynamically allocated memory. For example:

/* allocate some memory */
int *a = malloc(40);
/* reassign a without free-ing the memory before : you now have leaked memory */
a = malloc(40);
Community
  • 1
  • 1
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
1

The best option is not having two pointers, pointing to the same place, which are freed independently.
But if that's really what you need, then you need a reference count.

The following code implements a very simple reference count mechanism.
When you assign a second pointer to your data, you should use clone_x to increment the reference count.
Each time you free, use free_x, and it will free just once.

Note that this code isn't multithread-safe. If your code is multi-threaded, you need atomic operations, and you need to be very careful with how you use them.

struct x {
    int refcount;
    int payload;
};
struct x *create_x(int payload) {
    struct x *newx = malloc(sizeof(*newx));
    if (!newx) return NULL;
    newx->payload = payload;
    newx->refcount = 1;
    return newx;
}
void clone_x(struct x *myx) {
    myx->refcount++;
}
void free_x(struct x *oldx) {
    oldx->refcount--;
    if (oldx->refcount == 0) {
         free(oldx);
    }
}
ugoren
  • 16,023
  • 3
  • 35
  • 65
0

You can't. When free(a) is called it is no longer safe to access that memory.

Even if you malloc() new memory and assign the result to a, that memory could be anywhere.

What you're trying to do will not work.

Anders Abel
  • 67,989
  • 17
  • 150
  • 217
0

every allocated memory block should have an 'owner', a or b, if a is the owner, pointer b should not release that block, vice versa.

xwlan
  • 554
  • 3
  • 5