int main(void) {
int* p = (int*) malloc(sizeof(int));
int* q = (int*) malloc(sizeof(int));
*p = 10;
*q = 20;
p = q;
printf(“%d %d”, *p, *q);
free(p);
free(q);
}
Why does the above code contain use-after-free error? There's no more expression after free(p) and free(q). Obviously we are not using them anymore!
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!
You set p to q, so you are free()ing it twice.
Since q and p point to the same memory at the point you are freeing them, you're effectively freeing the memory twice.
Because here:
p = q;
...you're throwing away the old value of p. You now have two copies of the pointer that was returned by the second malloc, and none of the pointer that was returned by the first malloc.
So then here:
free(p);
free(q);
...the same pointer value gets passed to free twice: use-after-free error. The other pointer value never gets passed to free at all: memory leak.
It's a fundamental memory manipulation error!
Never do so!
You allocate memory at pointer p and after that you just rewrite pointer at p=q.
Previous value of pointer you lost, p is a lost pointer!
You can never free the memory allocated above for pointer p! It's a lost memory block for p.
It's memory leak... Try to free it at line free(p) in real free memory allocated for pointer q, but not for p!.
Next line free(q) is another try to free the same memory that was freed in previous line. That will be unpredictable behavior depending on the system it may be nothing special, and may be an error at program finish.
You must replace line free(p) before line p=q.
And always before rewrite pointer with previously allocated memory free them! Consider it a strict rule!
Related
I would like to know, when is the pointer p released in the code? Is it considered as a local variable and released at the end of foo function?
Also, when is *p released? I'm assuming it's never released.
I know that free releases the memory allocated by malloc. But I'm having trouble understanding the difference between p and *p, which one is considered to be "the memory" which is released ?
int foo()
{
int *p = (int*) malloc(sizeof(int));
.
. //free is not called
}
Inside a function body, int *p tells the compiler (or C implementation) to allocate memory for p. This allocation is automatic, and the release of the memory used for p is automatic when execution of the block the declaration is in ends.
When malloc(sizeof(int)) executes, it attempts to allocate enough memory for an int. This allocation is manual. The memory is released only when the program executes a call to free or some related routine that frees memory (such as realloc to allocate new memory and free the old memory).
The allocations of the memory for p and the memory that p points to are unrelated. There is no binding between p and *p other than the fact that the address of *p is is stored in p. You could do this:
{
int *q;
{
int *p = malloc(sizeof *p);
// Now p points to allocated memory.
*p = 3;
q = p;
// Now q points to the allocated memory.
}
// Now p no longer exists in the C model of computing.
// The memory used for p has been released.
// The memory allocated with malloc is still allocated.
printf("%d\n", *q); // Prints “3”.
free(q);
// Now the allocated memory has been released.
}
After the call to malloc, p will contain the address of the memory allocated by malloc.
So p is a (local) variable and *p is the allocated memory.
The allocated memory (*p) is released by a call to free, which never occurs in your code (this is called a "memory leak").
The local variable p is on the stack and is automatically released when the function returns (but *p is not automatically released!)
There are two pieces of memory involved - the variable p, and the int object p points to.
int * int
+–––+ +–––+
p: | | –––> | |
+—––+ +–––+
Space for the variable p is allocated on entry to foo and released when the function exits.
Space for the int object that p points to (which we refer to with the expression *p) is allocated by the call to malloc, and is not released until you call free (or until the program terminates).
When foo exits, the variable p ceases to exist. The memory that p pointed to is still allocated, but unfortunately you can no longer access it.
I've got the following faulty piece of code in C and I am wondering if there will be a memory leak or if there will be a pointer which is pointing to a free memory location.
int* p = (int*) malloc(sizeof(int));
p = NULL;
free(p);
Yes it will leak memory. You assign p to NULL before freeing the contents it's pointing to. One quick change will fix it:
int* p = malloc(sizeof(int));
free(p);
p = NULL;
The difference here is we give free the address allocated by malloc before setting p to NULL. In general setting a pointer to NULL will not free the contents, but will allow you to check if the pointer is valid or not which can have a lot of practical applications.
You will have a memory leak.
After you assign NULL to p, you no longer have a way to refer to the memory you allocated with malloc.
Your call to free will try to free NULL, doing nothing.
The following will correctly free the memory:
int *p = malloc(sizeof(int));
free(p);
p = NULL;
Note that you don't need to set p to NULL after freeing, you only really need the first two lines.
I understand that variables declared within a function have automatic storage. Does this mean it's not necessary to free pointers (p below) that have been explicitly allocated within a function call using malloc?
void f() {
int *p;
p = malloc(sizeof(int));
*p = 1;
printf("%p %d\n", p, *p); // 0x7fc135c02850 1
free(p); // is this necessary?
}
int main() {
f();
}
(Note that I used a pointer to an int here, but the question applies to any pointer that's a return value of malloc and friends.)
I'm guessing no, since malloc allocates memory on the heap and not the stack; thus the memory p points to won't automatically be deallocated when the stack frame for f() is popped.
p itself is automatic storage, and it will disappear when the function ends. What it points to however does need to be free()'d, at some point. For example, you could return the malloc()'d memory from the function, and free() it later on - p has still disappeared
The memory you allocate with malloc() needs to be free()'d. In your case, automatic storage applies to the variable p itself, but not to the memory you allocated! When you use free(p), you free the memory p points to and not the p variable itself.
Correct, a call to free is necessary.
If you ask for memory allocate manually, you must free manually the space you asked for. So free is necessary there
For example:
void heaptest(){
int *a;
a=(int*)malloc(1024*4);
int i=1024;
while(i--){
*a=i;
//printf("%d",*a);
a++;
}
free(a);
}
When the 'a' was used as a pointer, assume it points to address "0x20000". And the scope of this heap area is from 0x20000 to 0x21000. totally 4096 bytes.
after the while loop, the 'a' was pointed to 0x21004, which is actually out of the scope of the defined heap. if we free the heap using
free(a)
Will this heap be freed successfully?
For my observation, when I use this func in Visual Studio. it will show
Invalid address specified to RtlValidateHeap
and the value of a is 0x21004 before the free() operation whenever whether there is a printf() function in the while loop.
When I use this function on Keil-MDK for STM32F7(Cortex M7), it shows nothing but before the free operation. the value of 'a' will become 0x00000;
But when I add the printf() function shown in the code. the value of 'a' will back to the initial value 0x20000.
So, the final question is, could we change the value of the heap pointer? or assign it back to the initial value every time before the free() operation?
Will this heap be freed successfully?
It is impossible to say. You invoke undefined behavior by passing a pointer value to free() that was not returned by malloc() or one of the other allocation functions. That could turn out to manifest as freeing the block into which the pointer points, but more likely it produces an error, or worse: silent memory corruption.
Note in particular that it is the pointer value that matters. The variable, if any, in which you store the pointer value has nothing directly to do with it.
could we change the value of the heap pointer?
In the sense that the pointer is a value, no, you can no more change it than you can change the value 1. But you can cause a variable in which that value is stored to instead contain a different value. You may even be able to do so in a way that allows you to recover the original value, so as to retain the ability to free the allocated memory.
You need to free the address your were given. What you do to the code's variables in between does not matter.
This is valid:
char * p = malloc(42);
p++;
p--;
free(p);
This as well:
char * p = malloc(42);
char * q = p:
/* p += 43; */ /* Invokes UB, as making q point more then just one past the object. */
q += 42; /* Just one past the allocated memory. */
q -= 42;
free(q);
This isn't
char * p = malloc(42);
p++;
free(p);
This neither:
char * p = malloc(42);
p--;
free(p);
An address passed to free must have been obtained as the return value of malloc/calloc/etc. Passing any other pointer invokes undefined behavior.
From the MSDN page for free:
The free function deallocates a memory block (memblock) that was
previously allocated by a call to calloc, malloc, or realloc. The
number of freed bytes is equivalent to the number of bytes requested
when the block was allocated (or reallocated, in the case of realloc).
If memblock is NULL, the pointer is ignored and free immediately
returns. Attempting to free an invalid pointer (a pointer to a memory
block that was not allocated by calloc, malloc, or realloc) may affect
subsequent allocation requests and cause errors.
Keep track of the original pointer so you can later pass it to free:
void heaptest(){
int *a, a_sav;
a=(int*)malloc(1024*4);
a_sav = a; // save the original pointer
int i=1024;
while(i--){
*a=i;
printf("%d",*a);
a++;
}
free(a_sav); // free the saved pointer
}
Calling free with an argument that does not point to an adress allocated via malloc, calloc or realloc is undefined behavior. You have absolutely zero information on what it will do. Try something in this form.
void heaptest(){
// Declare a const to make sure we free the right adress in the end
int * const a = (int*)malloc(1024*size_of(int));
int i=1024;
do {
// This will loop from a[0] to a[1024] which is what I assume you meant to do
a[1024-i] = i;
} while (--i);
free(a);
}
It's hard to say if this program does what you wanted. You can change i or the index or the right hand side of the assignment to suit your needs but don't do the loop like you did because it's way more error-prone.
I've just written a function that returns a pointer to a block of memory allocated by malloc. If I call free() on the returned pointer, will this free the memory?
I tried reading up on this, but I can't find anything that says whether you can call a different pointer pointing to the same location and whether that will free all the memory or not.
This is probably majorly basic, I think I can't find the info because I'm searching for it wrong.
Any help appreciated!
Yes calling free will free the memory. Its not the pointer that get freed but the memory that the pointer points to that is freed.
You must pass to free() the value obtained from malloc().
int *x = malloc(42 * sizeof *x);
int *p = &x[0];
free(p); /* ok, same as free x; x and p have the same value */
Edit: another example
int *x = malloc(42 * sizeof *x);
for (k = 0; k < 24; k++) *x++ = 0; /* zero first 24 elements */
free(x - 24);
It's not entirely clear what you're asking here, but if what you're asking is:
Can I call free() on a pointer which points to a location within the allocated block?
then the answer is "no" -- you must pass free() the exact pointer which you got back from malloc(). Trying to free() an internal pointer, or a pointer to memory which was not allocated by malloc(), memory corruption or a crash are likely to occur.