You have two problems here.
First, you are deleting the same heap variable twice:
free(p);
free(q);
Second, you have a memory-leak, because the variable created by p is no longer accessible.
Notice that onebyone's comment is really important. If you change the line:
p = q;
into:
*p = *q;
There would be no problems at all in your code :) Hello Pointers!
Answer from Khaled Alshaya on Stack OverflowYou have two problems here.
First, you are deleting the same heap variable twice:
free(p);
free(q);
Second, you have a memory-leak, because the variable created by p is no longer accessible.
Notice that onebyone's comment is really important. If you change the line:
p = q;
into:
*p = *q;
There would be no problems at all in your code :) Hello Pointers!
You set p to q, so you are free()ing it twice.
Videos
Whenever I hear about a software vulnerability, most of the time it comes down to use after free. Why is it so? Doesn't setting the pointer to NULL would solve this problem? Here's a macro I wrote in 5mins on my phone that I believe would solve the issue and spot this vulnerability in debug build
#if DEBUG
#define NIL ((void*)0xFFFFFFFFFFFFFFFFUL)
#else
#define NIL ((void *)0)
#endif
#define FREE(BLOCK) do { \
#if DEBUG \
if (BLOCK == NIL) { \
/* log the error, filename, linenumber, etc... and exit the program */ \
} \
#endif \
free(BLOCK); \
BLOCK = NIL; \
} while (0)Is this approach bad? Or why something like this isn't done?
If this post is stupid and/or if I'm missing something, please go easy on me.
P.S. A while after posting this, I just realised that I was confusing use after free with double freeing memory. My bad
I'm interested on understanding deeply UAF. I truly don't understand why it is a problem?
Why a simple null pointer assignment after a free is not systematic or as part of C/C++ language?
So, do you have any literature or pointer? :-)
Thanks
Freed memory doesn't belong to you anymore. But that doesn't mean it disappears or gets changed in any way. Why would your program bother? It would be a waste of time. It probably just marks the memory as available for use by subsequent malloc()s, and that's it. Or it might not. Using memory that doesn't belong to you might do anything: return wrong values, crash, return right values, or run a flight simulator game. It's not yours; don't mess with it and you'll never have to worry about what it might do.
The C standard defines the behavior of the free function:
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation.
which means that a later call to malloc (or something else) might re-use the same memory space.
As soon as a pointer is passed to free(), the object it pointed to reaches the end of its lifetime. Any attempt to refer to the pointed-to object has undefined behavior (i.e., you're no longer allowed to dereference the pointer).
More than that, the value of the pointer itself becomes indeterminate, so any attempt to refer to the pointer value has undefined behavior. Reference: N1570 6.2.4p2:
If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.
It's true that free()'s argument is passed by value (like all C function arguments), and so free can't actually modify the pointer. One way to think of it is that the pointer has the "same" value before and after the call, but that value is valid before the call and indeterminate after the call.
It's likely that an attempt to refer to the pointer value, or even to dereference it, will appear to "work". That's one of the many possible symptoms of undefined behavior (and arguably the worst, since it makes it difficult to detect and diagnose the error).
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;
I'm sorry because I know that's going to sound really silly, but I am not sure I understand what free does in C. Does it delete the pointer that points to that chunk of memory we allocated to a value? Does it delete the value itself and the pointer? If it only deletes the pointer, what use is the value afterwards, if we don't keep the address?
You should call free only on pointers which have been assigned memory returned by malloc, calloc, or realloc.
char* ptr = malloc(10);
// use memory pointed by ptr
// e.g., strcpy(ptr,"hello");
free(ptr); // free memory pointed by ptr when you don't need it anymore
Things to keep in mind:
Never free memory twice. This can happen for example if you call
freeonptrtwice and value ofptrwasn't changed since first call tofree. Or you have two (or more) different pointers pointing to same memory: if you call free on one, you are not allowed to callfreeon other pointers now too.When you free a pointer you are not even allowed to read its value; e.g.,
if (ptr)not allowed after freeing unless you initializeptrto a new valueYou should not dereference freed pointer
Passing null pointer to
freeis fine, no operation is performed.
Think that the computer has a whole bunch of memory not (yet) used by your program. Now you need some more memory and you ask your computer to give you some more (for example, a large buffer). Once you are done with it, you want to return it to the computer.
This memory is called the heap. You ask for memory by calling malloc() and you return it by calling free();
char *buffer;
buffer = malloc(512); // ask for 512 bytes of memory
if (buffer==NULL) return -1; // if no more memory available
...
free(buffer); // return the memory again
When I search for the answer, all I see is references to the fact that this is undefined behavior in C. But that answer isn't satisfying to me because it seems to be a problem that all languages go to great lengths to avoid. Why can't the memory management system simply not do anything when a pointer is freed a second time? Why do languages seem obligated to treat this as such a serious problem?