Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why exactly should I not call free() on variables not allocated by malloc()?

I read somewhere that it is disastrous to use free to get rid of an object not created by calling malloc, is this true? why?

like image 472
ultrajohn Avatar asked Apr 22 '10 05:04

ultrajohn


2 Answers

By the standard, it's "undefined behavior" - i.e. "anything can happen". That's usually bad things, though.

In practice: free'ing a pointer means modifying the heap. C runtime does virtually never validate if the pointer passed comes from the heap - that would be to costly in either time or memory. Combine these two factoids, and you get "free(non-malloced-ptr) will write something somewhere" - the resutl may be some of "your" data modified behind your back, an access violation, or trashing vital runtime structures, such as a return address on the stack.

Example: A disastrous scenario:
Your heap is implemented as a simple list of free blocks. malloc means removing a suitable block from the list, free means adding it to the list again. (a typical if trivial implementation)

You free() a pointer to a local variable on the stack. You are "lucky" because the modification goes into irrelevant stack space. However, part of the stack is now on your free list.

Because of the allocator design and your allocation patterns, malloc is unlikely to return this block. Later, in an completely unrelated part of the program, you actually do get this block as malloc result, writing to it trashes some local variables up the stack, and when returning some vital pointer contains garbage and your app crashes. Symptoms, repro and location are completely unrelated to the actual cause.

Debug that.

like image 95
peterchen Avatar answered Sep 30 '22 03:09

peterchen


Please have a look at what undefined behavior means. malloc() and free() on a conforming hosted C implementation are built to standards. The standards say the behavior of calling free() on a heap block that was not returned by malloc() (or something wrapping it, e.g. calloc()) is undefined.

This means, it can do whatever you want it to do, provided that you make the necessary modifications to free() on your own. You won't break the standard by making the behavior of free() on blocks not allocated by malloc() consistent and even possibly useful.

In fact, there could be platforms that (themselves) define this behavior. I don't know of any, but there could be some. There are several garbage collecting / logging malloc() implementations that might let it fail more gracefully while logging the event. But thats implementation , not standards defined behavior.

Undefined simply means don't count on any kind of consistent behavior unless you implement it yourself without breaking any defined behavior. Finally, implementation defined does not always mean defined by the host system. Many programs link against (and ship) uclibc. In that case, the implementation is self contained, consistent and portable.

like image 41
Tim Post Avatar answered Sep 30 '22 03:09

Tim Post