Reusing freed pointers in C

2019-01-25 08:01发布

问题:

There are many questions on this website regarding freeing pointers after use and, further, setting them to NULL. Arguments are fierce and the topic is seemingly divided equally. For example: This question. I am confused about freeing pointers in general.

Imagine you have a pointer to some memory space. After using the space, you free the pointer but do not set it to NULL. Later, you have another pointer that calls malloc(), or some analog, and it is allocated memory including the memory freed earlier (that the original pointer still points to). If this new pointer writes in this memory block, what happens? Intuitively nothing would happen, but the OP in the link provided earlier writes that it would crash the program.


So my questions are:

  1. Given a freed pointer, what is keeping you from reassigning that pointer to a new memory location? Why is it 'bad' practice to reuse freed pointers? If calling free(ptr) only returns this memory to the OS, why can you not reassign the pointer so other memory locations and reuse it?

    char *ptr = malloc(sizeof(*ptr)); //first allocation
    free(ptr); //release memory 
    ptr = NULL; 
    ptr = malloc(sizeof(*ptr)); //reallocate
    
  2. Why would writing to a memory block that was previously freed, that still has the original pointer to it, cause the program to crash? -- See the first paragraph of the first post to the question linked above (if I misinterpreted the intent of this paragraph, please explain because it is not explicit whether that pointer is used again to write the memory or a new pointer is created.)

回答1:

Given a freed pointer, what is keeping you from reassiging that pointer to a new memory location?

Technically, nothing. You do not even need to set ptr = NULL in between of freeing and re-assigning the pointer. When freeing and re-assigning are separated by other lines of code, however, setting the pointer to NULL may improve readability slightly.

Why would writing to a memory block that was previously freed, that still has the original pointer to it, cause the program to crash?

Simply holding a pointer to a block of memory accessible through another pointer is absolutely OK, as long as your program does not try dereferencing that pointer. Unfortunately, even if you dereference the freed pointer, it would not necessarily cause your program to crash: more often than not, such behavior would go unnoticed. It remains an undefined behavior, though. Another part of your program may have written data incompatible with what you expect, in which case you will see bugs that are extremely hard to find or explain.



回答2:

  1. Since the original pointer now points into allocated space once more, it is possible to use it. However, it is a bad idea to do so; the code that allocated the memory thinks it has control of it and will be upset if the code using the old pointer modifies the data. Also, it is likely that the new code is storing different types of data from what the old pointer expects, so the code using the old pointer won't understand what's going on.

    In your example, reusing the pointer variable is a non-problem. The value returned by the second malloc() may be the same as was returned by the first, or it may be different, but (even without the assignment of NULL) reusing the pointer like that is fine (as long as you subsequently free the second allocation).

  2. If the space is freed, it is possible (albeit rather unlikely) that the space was unmapped by the O/S and is no longer a part of the valid addresses available to your program. It is more likely that confusion over what the data means will cause the program to crash than that the space was returned to the O/S, but either is possible.

Summary: don't use old pointer values to access re-allocated memory — it will lead to unhappiness.



回答3:

"Why would writing to a memory block that was previously freed, that still has the original pointer to it, cause the program to crash? -- See the first paragraph of the first post to the question linked above (if I missinterpreted the intent of this paragraph, please explain because it is not explicit on whether that pointer is used again to write the memory or a new pointer is created.)"

I think reusing the same memory space after it has been free'ed is equal to 'crime', atleast for Kmem(slab allocation) based designs(I think mostly used in linux..correct me if I am wrong).

To understand the reason we need to see how things work inside(you can skip and just read the conclusion at the end):

  1. OS divides the whole dynamically allocatable memory into pages. Each of these pages are assigned to hold objects(and a few for managing those objects and pages them sleves). One page can have objects of only one memory size. E.g. if the page size is 1024 bytes and the object that the page will be managing is 32 bytes. Then the whole page 'CAN' be divided into maximum of 1024/32 objects.

In simple embedded systems, many pages in memory are divided into objects usually of size 2^y(e.g. 8 bytes, 16 bytes etc). So when you request z bytes of memory by malloc, where

16 < z <=32

The system returns one object from the pool of 32 byte objects held in some page having free objects. After assigning you this object, OS makes changes to the 'slab' data structure and marks the object at a given address as non-free.

When you call free(), the object is returned to the slab pool as a free object and the OS can reassign it if other malloc call happens. This call can be made by your code or some other component running in the os.

**So if you reuse the free'ed memory which the os had previously assigned to your code. Then you might be writing to some memory location which might be used:

  1. By your code OR
  2. Some other component running in the OS **

Further, some other component who the OS re-assigned the pointer too could also over-write on your data.

And this can cause severe data corruption.

Further, make sure that you dont write more data to the memory, than what you requested through malloc(). Doing this can cause :

  1. Some other components data being corrupted
  2. Or Some memory management data structure being corrupted(like slabs, cache-managers etc).


回答4:

You're not using the malloc() function corrrectly, please check the docs, this is the right usage because it returns a pointer:

char *b;
b = (char *)malloc(42*sizeof(char));

Also sizeof() must be used to determine the size of the contents of the pointer (ie. char or whatever), not the size of the pointer itself (unless you are storing an array of pointers, not the case here).

There is no need to set the freed pointer to NULL, it just doesn't make any sense. Also there is no problem in re-allocating space for a freed pointer, since malloc() will return a pointer to the new memory block and you'll assign your previously freed pointer to the one returned my malloc().

Please note that if you want to resize the memory block there is realloc().



标签: c pointers free