Reputation: 1219
During my tests, I have found that it is possible to use pointer after free(). I have the following code:
typedef struct{
int module_id;
int adc_id;
struct config_line * pnext;
} config_line;
config_line * create_list()
{
config_line * phead = (config_line *) malloc(sizeof(config_line));
phead->pnext=NULL;
phead->module_id = 1;
phead->adc_id = 2;
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
free(phead);
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
phead->module_id = 2;
phead->adc_id = 5;
printf("module_id=%d adc_id=%d\n",phead->module_id, phead->adc_id);
}
The output of this code is:
module_id=1 adc_id=2
module_id=0 adc_id=2
module_id=2 adc_id=5
Why after free(phead) I can get access (read and write) to pointer? Why there is not segmentation fault?
Upvotes: 8
Views: 16773
Reputation: 213563
The data is freed during the free()
call. Accessing a pointer after calling free()
gives a so-called "dangling pointer", it's undefined behavior and anything can happen. What is undefined behavior and how does it work? Specifically, it is UB because of the last sentence of C17 7.22.3.3:
void free(void *ptr);
The
free
function causes the space pointed to byptr
to be deallocated, that is, made available for further allocation. Ifptr
is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call tofree
orrealloc
, the behavior is undefined.
In general, there's no magic "erased state" in RAM memories of computers. The values will persist in memory until that cell is used for something else. "Erasing" something merely giving up ownership of those memory cells.
It's good practice to write NULL
to pointers after calling free()
for this reason, to mark the pointer as not pointing to anything valid.
Upvotes: 2
Reputation: 42083
When you call free(phead)
, the memory phead
points to is being freed, but the value of phead
stays untouched, making the phead
a dangling pointer. Accessing the memory that has already been freed produces undefined behavior.
It is a good practice to assign NULL
to the pointer once you free the memory it points to:
free(phead);
phead = NULL;
Upvotes: 16
Reputation: 15632
Why might a chicken continue to run and jump around despite it's head being chopped off? Note that this doesn't always happen; some chickens might cease moving immediately, while others might continue to run around for months. When it does happen, it happens because it happens. Does that mean we should cut our pets heads off?
Like cutting our pets heads off, using memory that has been freed is a bad idea. That doesn't mean it will produce negative results; your program might continue to run as expected on your machine, while if (fubar)
(where fubar is your invalid pointer) might be enough to cause your program to malfunction on other implementations.
This idea freedom for the implementation to define (or not) the behaviour is formally known as undefined behaviour; the behaviour is undefined because the C standard, a set of documents dictating how C implementations should behave, doesn't define the behaviour. Therefore, like cutting our pets heads off, we should avoid all undefined behaviour.
Upvotes: 6
Reputation: 8923
Because freeing memory (a pointer) just puts back that memory on the free memory pool. The memory doesn't just disappear, and it's contents are not cleaned out till when that memory is allocated again and written to.
So, it is very much possible to access the memory after it's been freed up. Just not a good idea as you can imagine, because it can be allocated anytime, and modified.
Upvotes: 5
Reputation: 9685
Because the memory is still mapped into your process, but isn't allocated. There are two levels of memory management that go on in a C program: Firstly, the kernel gives you pages you can write to. If the process needs more memory that it has mapped, it has to request more from the kernel (sbrk). That comes in large chunks though, so malloc slices it up into chunks for you, requesting more pages as needed, but using where possible memory already allocated to the program. free can't return a page until all the allocations that used it have been freed.
So, the memory access violations the kernel gives you (SIGSEGV) are rather coarse, and can't pick up most memory errors, only things that are fatal from a kernel point of view. You're free to trash your malloc's tracking data, read past the end of most allocations and after many frees, and so on.
Don't ever commit memory errors though. Run your app with valgrind, which uses a very strict VM, to check for all errors and squash them immediately.
Upvotes: 8
Reputation:
Because using an invalid pointer invokes undefined behavior. And that means that the behavior is... well... undefined. It's not obliged to crash.
Upvotes: 24