简体   繁体   中英

Using pointer after free()

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?

Because using an invalid pointer invokes undefined behavior. And that means that the behavior is... well... undefined. It's not obliged to crash.

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;

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.

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.

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.

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 by ptr to be deallocated, that is, made available for further allocation. If ptr 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 to free or realloc , 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM