16

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.)

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • I think the answer to 2 might have something to do with the OS potentially using freed memory for another process. – FreelanceConsultant Jul 25 '13 at 16:45
  • From what I read, when memory is allocated for a program, through malloc() or some other analog, then that memory block is restricted for use only by the calling program. Likewise, a program cannot use memory that was not allocated for it. – sherrellbc Jul 25 '13 at 16:46
  • Reusing a freed pointer in the link you give does not mean allocating it again - it means using it after free when you *have not* alloc'ed it to somewhere else. 1. is fine – doctorlove Jul 25 '13 at 16:47
  • @EdwardBird: That would only be true in certain kinds of architectures like small embedded machines. In a mainstream operating system like Linux, Windows, and MacOS, etc., the process boundary makes pointers in other processes completely inaccessible and irrelevant. – wallyk Jul 25 '13 at 16:48
  • My confusion lies in the fact that the memory was returned to the OS, but still has a pointer to it. Then another pointer is allocated that same memory (by chance) later in the problem. Why would the program crash in this circumstance? -- Again, I could be interpreting the post incorrectly. Perhaps if you are a seasoned programmer then it all makes sense (the post), but to someone rather inexperienced the wording seems ambiguous. – sherrellbc Jul 25 '13 at 16:48
  • 2
    When you ask “Why is it ‘bad’ practice to reuse freed pointers?”, are you asking about reusing the pointer by assigning it a new value or about reusing the pointer by using the value it previously had? After you `free(x)`, you may not use `*x` for anything, but you are entirely free to assign `x` a new value. – Eric Postpischil Jul 25 '13 at 16:56
  • I probably should have said "your own program might overwrite what the pointer is pointing to " then – FreelanceConsultant Jul 25 '13 at 16:56
  • Is the first `*` in `*ptr = malloc(sizeof(*ptr));` a typo? Should it be `ptr = malloc(sizeof(*ptr));`? – Eric Postpischil Jul 25 '13 at 16:57
  • @Eric The first use of the dereference was intentional; that line is a delcaration of the character pointer. As for the second use, I was unsure. In all honesty, I did not think it was correct when reassigning the pointer to use the * again, but I figured that someone would post it was incorrect; thus, why I added it anyway. – sherrellbc Jul 25 '13 at 17:00
  • And for your first comment, I did mean reusing the pointer after reallocation - but others have made it clear that this use is legal. I suspected it was, but the post I linked to was ambiguous on how the pointer was "reused." – sherrellbc Jul 25 '13 at 17:02
  • @sherrellbc: There is no dereference operator in the declaration. In the declaration `char *ptr = …`, the `*` is part of the syntax of the declaration. This is not an expression or assignment, so `*` is not an operator. (And, although `ptr` is given a value, that is initialization, not assignment.) In spite of the presence of `*`, the initialization gives a value to the thing being declared, `ptr`, not to `*ptr`. In the later assignment `ptr = malloc…`, you use `ptr`, not `*ptr`, because you want to assign a value to `ptr` and not to the thing it points to. – Eric Postpischil Jul 25 '13 at 17:03
  • @Eric Sure, but I was referring to the symbol as the 'dereferencer' of sorts I guess. I was not implying the declaration was dereferencing the pointer. And yes, I realize the mistake on the reallocation line. I addressed the issue in an earlier post here. I was uncertain and was relying on someone pointer it out. Thank you. – sherrellbc Jul 25 '13 at 17:14
  • @Eric Oh wait, sorry I read your initial post wrong. I thought by the first use of * you meant the declaration line - hence my response. Now I realize you meant the * use on *ptr on the third line. It was very obvious, I just read it wrong. – sherrellbc Jul 25 '13 at 17:23

4 Answers4

15

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I believe the second question you are answering is: “If I do `… free(x); y = malloc(size); *y = foo;`, and this `malloc` returns space previously pointed to by `x`, will the program crash?” If so, then this is not undefined behavior. The fact that `x` contains an address that overlaps the space `y` points to is irrelevant, as long as `*x` is not used. – Eric Postpischil Jul 25 '13 at 16:54
  • @EricPostpischil Ah, I assumed that the idea was to use `*x` after freeing it and without re-assigning, suggesting that since the same region of memory has been allocated to another pointer in the same program, it should be legal. I edited my answer to reflect that, thanks! – Sergey Kalinichenko Jul 25 '13 at 17:04
  • @dasblinkenlight What you answered was not exactly my question, but it helped to clairfy some things. Thank you. – sherrellbc Jul 25 '13 at 17:18
  • @Eric Exactly, this is why I asked this question to begin with. I did not think the program should crash in these circumstances. The link provided was not explicit on their use of 'reusing' a pointer. I was not sure. – sherrellbc Jul 25 '13 at 17:18
4
  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.

Community
  • 1
  • 1
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • I thought that when memory allocated by a program is freed, then it is returned to the OS. By unmapped [by the OS], do you mean removing the program's authority over writing in the memory block? If so, that is what I thought calling something like free() does anyway. – sherrellbc Jul 25 '13 at 16:55
  • I do not think this answer (or others) are answering the questions the OP intends to ask. There is a lack of clarity about what sort of “reusing a pointer” is intended. – Eric Postpischil Jul 25 '13 at 17:00
  • Unmapping is fairly expensive, and the `free()` routine is seldom written to actually unmap the memory. The freed space normally goes into a list of blocks of memory available for reuse. – Jonathan Leffler Jul 25 '13 at 17:05
  • @EricPostpischil: OK — please go ahead and submit your own answer that answers the question you see being asked. – Jonathan Leffler Jul 25 '13 at 17:07
  • @Jonathan So, the blocks of available memory is not returned to the OS, but rather is pushed to a sort of temporary storage location in case the programs needs more memory allocation again? – sherrellbc Jul 25 '13 at 17:12
  • That's the normal mechanism, yes. It may or may not be reallocated immediately — that depends on the algorithms used inside the allocator package, and whether the block is big enough to satisfy the next request, and so on. – Jonathan Leffler Jul 25 '13 at 17:27
0

"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).
Pranaysharma
  • 537
  • 6
  • 13
-1

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().

Paul
  • 20,883
  • 7
  • 57
  • 74
  • THE assignment of `malloc` to `*ptr` instead of `ptr` is just a mistake, not an intended part of the question. And calculating the size from the pointed-to type, as with `ptr = malloc(sizeof *ptr)`, is correct. – Eric Postpischil Jul 25 '13 at 16:59
  • Anyway there is a mistake, it doesn't matter if it's a typo or not (I don't think so because it appears twice), I thought it's good to mention it since other users may take that for granted. About the `sizeof(*ptr) thing, sorry, I misread the code. I somehow thought that he was doing `sizeof(char*)`. – Paul Jul 25 '13 at 17:04
  • The code block I posted was not actual code I use, it was written to simulate statements that would be used in practice. Each line would have lots of code in between and were not meant to be sequential. Also, the way I used malloc is fine. In this context, malloc allocates sizeof(*ptr) bytes, which evaluates to the size of a character -- which is the pointer's type. http://www.cprogramming.com/tutorial/c/lesson6.html – sherrellbc Jul 25 '13 at 17:05
  • I just said that above... The fact that I misread a part of you code. – Paul Jul 25 '13 at 17:06
  • I was writing that while Eric posted his comment. – sherrellbc Jul 25 '13 at 17:08
  • 1
    What you claim as "good practice" certainly isn't. It's never necessary to cast the result of `malloc()`, and `sizeof *b` is the same as `sizeof (char)` (namely `1`) but has the advantage that it adapts automatically to changes in the declaration of `b`. – Toby Speight Aug 22 '17 at 12:08