0

When I implemented my own version of malloc() in college, I used two linked lists: A free list and an allocated-buffers list (interspersed with calls to sbrk when I ran out). But now I have real-world issue: Our software malloc's buffers and puts them on linked lists where they may get freed hours later by code in one function or another. But very little code has the free() in the same function as the malloc()

This occasionally leads to a malloc'ed buffer being freed twice. Under Solaris, this was apparently not a problem because the app has been running for a looooong time. But running the code under Linux (RH) this bug suddenly has woken up.

I do not know the internal behavior of malloc() but it is obviously implementation-dependent. I do not know if the the Linux/gcc implementation maintains a list of allocated buffers. (The free list is a MUST; the allocated list? Not so much, I think.) Which leads me to the point of my questions:

  1. Does this implementation of malloc use a list of allocated memory areas?
  2. Is there a function (unofficial is fine by me) that will scan that list for a given pointer?

After reading a response my hmjd to a question by ant2009 my scheme, if the above answers are yes, is to replace calls to free() by a macro whose expanded code:

  • Checks if the pointer is null, in which case it skips the next few steps
  • Calls this mysterious function to insure it is still malloc'd
  • Frees is by the book using free()
  • Nulls the pointer as signal that it has been freed already; don't bother freeing again.

Such a function sure isn't in thI may e man pages but I would welcome. (As I write this, I am about to download glibc-2.17.tar.xz; find my answer there as well.)

Thanks. (Even for just reading this far!)

-- Jacob

Community
  • 1
  • 1
Jacob Salomon
  • 161
  • 1
  • 4
  • "very little code has the free() in the same function as the malloc()". Of course. There are two reasons for `malloc`: you can't use the stack because the allocation must outlive the calling function, or the allocation is too big to go on the stack. Only the last, rare case would have `free` in the same function. – MSalters May 10 '13 at 22:19

1 Answers1

1

Here is the big issue, rather than your crash...

you can't based on the address tell if the second free is intended for your object or another object that has been malloced in the mean time and is in use...

as to your points:

  • Checks if the pointer is null, in which case it skips the next few
    • free() is null safe in all modern implementations, wont matter.
  • steps Calls this mysterious function to insure it is still malloc'd
    • you still wouldn't know if it was the object you meant it to be.
  • Frees is by the book using free() Nulls the pointer as signal that it
    • I don't know what this means
  • has been freed already; don't bother freeing again.
    • this is the crux of the matter, once you are here you are in a bad state.

You have a bug, and you need to fight the urge to fix the C language, and fix your code...

NULL'ing pointers is good, but it is only a step, in that once you have handed a copy of the pointer off... nulling your local copy wont null the other copy...

if this is a place where it is needed for sure you could use another level of indifference.

void ** handle;
void ** handle2;

void * obj = malloc(5);

handle = &obj;
handle2 = &obj;

free(*handle);
*handle = NULL;

free(*handle2);
*handle2 = NULL;

then nulling obj could be helpful...

Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • AGree with the first part. Fix the bug. Disagree with the second part. That is going to introduce not dozens but hundreds of bugs where a `void**` is nulled instead of a `void*` and vice versa. It's C, not C++, so one must learn to be exact about memory use. (In C++ you'd use a `smart_ptr` and let it figure out when to free memory). – MSalters May 10 '13 at 22:22
  • well you can fix that by using a function or a macro to do the free and null. – Grady Player May 10 '13 at 22:23
  • A macro is half the solution. It prevents double frees through the same variable, but not through copies of that variable. It tends to give a false sense of security. – MSalters May 10 '13 at 22:27