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 Overflow
🌐
Reddit
reddit.com › r/c_programming › why is use after free error is so common?
r/C_Programming on Reddit: Why is use after free error is so common?
May 25, 2025 -

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

🌐
Medium
expl0it32.medium.com › demystifying-use-after-free-vulnerabilities-a-deep-dive-into-memory-safety-issues-78ee7f8d44c2
Demystifying Use-After-Free Vulnerabilities: A Deep Dive into Memory Safety Issues | by eXpl0it_32 | Medium
April 23, 2025 - A Use-After-Free (UAF) vulnerability arises when a program continues to access memory that has already been deallocated (freed). This happens in low-level languages like C or C++, where developers are responsible for managing memory manually.
🌐
GitHub
github.com › NVombat › Use-After-Free
GitHub - NVombat/Use-After-Free: CWE-416 Use-After-Free Vulnerability, Attack and Fix · GitHub
Free the chunks of memory using option 3. Select option 2 to allocate a chunk of memory for the password so that it can rewrite the contents of the previously allocated username chunk too. Use option 4 to log in and successfully exploit the vulnerability
Author   NVombat
🌐
CQR
cqr.company › web-vulnerabilities › use-after-free-vulnerability
Use-After-Free vulnerability | CQR
This code demonstrates a Use-After-Free vulnerability in C. The code allocates a block of memory using the malloc function and then frees the memory using the free function. However, the code then continues to access the memory by assigning ...
Find elsewhere
🌐
OWASP Foundation
owasp.org › www-community › vulnerabilities › Using_freed_memory
Using freed memory | OWASP Foundation
The simplest way data corruption may occur involves the system’s reuse of the freed memory. In this scenario, the memory in question is allocated to another pointer validly at some point after it has been freed. The original pointer to the freed memory is used again and points to somewhere within the new allocation.
🌐
Kaspersky IT Encyclopedia
encyclopedia.kaspersky.com › glossary › use-after-free
What is Use-After-Free? | Kaspersky IT Encyclopedia
February 18, 2026 - If after freeing a memory location, a program does not clear the pointer to that memory, an attacker can use the error to hack the program. UAF vulnerabilities stem from the mechanism of dynamic memory allocation.
🌐
Pub
ocw.cs.pub.ro › courses › cns › labs › lab-10
Lab 10 - Use After Free [CS Open CourseWare]
January 11, 2021 - This gives the attacker control over what data is accessed after the free. In terms of function calls on a Linux system, as attackers, we need to force a malloc of the same or similar size after the free.
🌐
Sternum IoT
sternumiot.com › home › what is the double free (cwe-415)?
What Is the Double Free (CWE-415)? | Sternum IoT
July 28, 2024 - This might allow an attacker to write values to arbitrary memory spaces and create an interactive shell with elevated privileges. Use After Free (CWE 416)—occurs when a program continues to use a memory pointer after it has been freed.
Top answer
1 of 3
21

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.

2 of 3
4

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

🌐
Caticx
caticx.com › home › what is use-after-free vulnerability? impact and mitigation
What is Use-After-Free Vulnerability? Impact and Mitigation | Caticx
September 26, 2025 - These issues are particularly common ... for error. A Use-After-Free (UAF) vulnerability occurs when a program continues to use a pointer to memory that has already been freed....
🌐
Reddit
reddit.com › r/learnprogramming › what does free do in c, exactly?
r/learnprogramming on Reddit: What does free do in C, exactly?
May 14, 2023 -

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?

Top answer
1 of 2
9
free deallocates the region of memory that the pointer points to. The pointer itself still exists, as a "dangling pointer". Its value still points to the same memory address, but that memory address is now no longer allocated. It might later get reused to store part of a totally different object, or even to store bookkeeping information for the heap itself. But whether or not that happens is unpredictable. So to avoid undefined behavior , you must not try to dereference a pointer after the object that it points to has been freed. Also, remember that a pointer is just a value, like any other type of value. If you copy the same pointer value into multiple pointer variables, and then free the object that they point to, all of the pointers are now invalid.
2 of 2
5
When you malloc some memory, the standard library does a few things: First, it checks to see if it has enough available memory within your process space already. If not, it will generally ask the operating system for some more memory and, if some is available, it will add this region to its list of "free" chunks. Next, it searches for a free chunk which is of the requested size or larger. All malloc allocations must necessarily be "contiguous," that is, if you ask for a slice of 1,000 bytes, you need to find a region of memory which is 1,000 bytes large or more. Once such a section is found, a couple of things happen. If it's particularly large, it might be split into a couple of chunks, so as to not waste space. If it's around the size you asked for, however, the chunk is probably taken as-is, even if it's slightly larger than what you asked for. The memory allocator will take the selected chunk, remove it from the "free" list, and write some special metadata to the beginning of that chunk to remind itself later about how big the chunk is, among other things. Finally, a pointer to the chunk (after the metadata that the allocator wrote) is returned to you, the caller. If any of these steps failed, you will be returned NULL instead. free uses that metadata I previously mentioned to do the inverse. When a pointer to memory is given to free, it looks for the metadata at the start of the chunk. From this, it derives the size of the memory allocation among other internal state for the allocator. It marks this chunk as no longer in use, then re-adds it to its list of "free" chunks. Since free is unable to reassign the variable or whatever you passed into it, you'll still maintain a pointer to this now-freed memory, even if it is now pointing to a chunk which may be reused in the future. As the other commenter said, this is why you should take special care to not touch this pointer once you've freed it; immediately reassign it to NULL or some other valid pointer to prevent this. Otherwise, you run the risk of writing into a region of memory which may be allocated by another part of your application—or, on an embedded system, another part of the system entirely. Note that a lot of this is a simplification (and partially reconstructed from memory about how the C stdlib allocator works). Actual implementations may vary greatly, but the overall idea is the same; you're telling the allocator that you no longer need the memory you asked for by freeing it, thereby returning it to the allocator to repurpose as needed. Also note that free doesn't do anything special with the memory you freed other than mark it as unused. It doesn't overwrite any data that was already there, nor does it somehow prevent accesses to this data after it's been repurposed.
🌐
Huntress
huntress.com › cybersecurity-101 › topic › what-is-use-after-free
Use-After-Free Explained: Master the Basics and Stay Secure | Huntress
A use-after-free vulnerability occurs when a program accesses a piece of memory that’s already been marked as available for someone else. This bug creeps into programs when memory is freed (released back for the system to reuse), but the software continues to use an old "pointer" (think shortcut or reference) to that memory.
🌐
Reddit
reddit.com › r/c_programming › can someone explain to me the *fundamental* problem with "double-freeing" a pointer?
r/C_Programming on Reddit: Can someone explain to me the *fundamental* problem with "double-freeing" a pointer?
January 7, 2025 -

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?

Top answer
1 of 32
167
The problem occurs when that memory gets allocated between when you freed it the first time and when you freed it the second time. Then it gets allocated again to yet another part of your program. Now you have two parts of your program using the same chunk of memory for different purposes, overwriting each other in the process. Then your program crashes and it's nowhere near where the double-free bug occurred.
2 of 32
27
Besides the "freeing some other structure's memory" problem if it gets reallocated after the first free, what happens depends on how the system actually keeps track of what memory is allocated and what is freed. I believe a lot of C allocators actually store a little bit of data just before the pointer they return to you, indicating things like are the previous and next blocks of memory also free (so they can be coalesched). When you free it twice this extra memory may not be there--or it may still be there, either of which could confuse the memory management system and cause it to crash or misbehave in other ways. OR, it could write something that said "this block has been free already" and actually no-op properly (assuming the memory has not already been handed to someone else). This is one of those undefined things that really is undefined because it has been implemented in multiple ways and they behave differently in this situation--as opposed to the undefined behavior which is just "Well when you access random memory we don't know what is going to be in it so of course it is undefined". I guess what I am trying to say is the behavior on any given implementation of the memory manager is probably "defined" (doesn't mean it will be good, of course, just predictable) but across the union of all memory managers it is undefined because it is "defined" in multiple ways.
🌐
SensePost
sensepost.com › blog › 2017 › linux-heap-exploitation-intro-series-used-and-abused-use-after-free
SensePost | Linux Heap Exploitation Intro Series: Used and Abused – Use After Free
In human-readable language this means that at some point of the implementation there was a logic flaw that caused a free() on a chunk, but despite being free()’d, its memory position is still referenced, effectively making use of the free’d chunk’s data after it has been set free.