I tried to compile the following code :
#include <stdio.h>
void main()
{
int *p = (int*) malloc(4*sizeof(int));
p++;
p++;
free(p);
}
But it gives me the following error.
* Error in `/home/a.out': free(): invalid pointer: 0x0000000001d04018 *
Aborted.
I think I am still within the allocated limits of size 4 ints. But then why invalid pointer. Can some one help.
You are invoking undefined behavior.
From free manual:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs.
It doesn't matter whether you are inside allocated region or not. The pointer must be the same that was allocated before.
The rationale for being it undefined is that typical implementation (this is implementation defined) must remember other metadata related to the allocation, e.g. the allocation size, in some data structure in order to free them later. If ptr is not same as returned by allocation function then there is no way to lookup into this data structure to get those metadata during freeing.
The free() function can only operate on a pointer that has been directly allocated with malloc() or any of its companions.
If you change the pointer you'll have errors like this, that modified pointer was never allocated.
"Close enough" does not count. It must be identical to the pointer you got in the first place.
The contract for malloc and free is fairly simple. The pointer value (the address) you pass to free must be exactly a pointer value you got from malloc.
Exactly, and not in the same block, however close. It must match exactly. You modify the pointer before passing it back (you increment), so you violate that contract. This is going to cause undefined behavior. And you experience it in the from of a crash. It could be worse, it could appear to work. Until it blows up in your face later for no apparent reasons. That's the nature of undefined behavior. Avoid it.
Related
When I run the following code:
int main(int* argc, char** argv) {
int* array = malloc(5 * sizeof(int));
free(array + 3);
}
I get the error pointer being freed was not allocated. My intuition is that instead of trying to free the fourth element of array, free tried to free the thing living 3*sizeof(int) bytes after its last element. Is this correct? If so, then why does this happen? And is the behaviour resulting from the execution of this programme always predictable, or is it undefined of implementation-specific?
free expects you to use the very same address returned from malloc or otherwise anything might happen. The malloc call allocates a whole segment per call, in this case 5 int large. It doesn't make sense to free up parts of this segment, that's not how the heap works.
Heaps first allocate a segment header which is internal information that contains size etc. Then after that header, all the data. This header part isn't visible to the programmer and how it is implemented is OS and/or C library specific.
Indeed in your case you pass an address which sits 3*sizeof(int) bytes into the data part of the segment, which isn't a valid address since free needs the initial address used by malloc in order to know where the internal header of that segment starts. When you pass the wrong address to it, it might grab some other part of random data and treat that as the header. The behavior is undefined.
(You can however pass a null pointer to free() and that's guaranteed to be a no-op.)
From specification of free():
Synopsis
#include <stdlib.h>
void free(void*ptr);
Description
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if the argument does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to free or realloc, the behavior is undefined.
Thus, what you're trying to do is undefined behavior
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf
malloc allocates a block of memory.
You can only de-allocate (free) this block. You cannot free individual elements or a part of the block.
You can re-allocate (realloc) this block to make it larger or smaller.
I was reading to Dangling Pointer and found it's a good habit do this, to prevent oneself from dangling pointer error.
free(ptr); // free the ptr
ptr = NULL;
Now I decided to test this with a sample vanilla C code.
CASE_1
char *ptr = malloc(10);
...
...
free(ptr);
ptr=NULL;
// Just to check what happen if I call free more than I once
free(ptr)
ptr=NULL;
All work fine. Until I decided to wrap the free and the pointer NULL assignment in a function I named it safefree
void safefree(char *pp) {
free(pp);
pp = NULL;
}
CASE_2
Now, when I ran the above method more than 1 (like this)
safefree(ptr);
safefree(ptr);
I get the following error.
malloc: *** error for object 0x7fd98f402910: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
I happen to understand the error (pointer being freed was not allocated)
but I fail to understand why it doesn't fail in the CASE_1 and fails in latter part of the sample code.
First, let's review the behaviour of free(). Quoting C11, chapter ยง7.22.3.3
void free(void *ptr);
The free function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. If ptr is a null pointer, no action occurs. Otherwise, if
the argument does not match a pointer earlier returned by a memory management
function, or if the space has been deallocated by a call to free or realloc, the
behavior is undefined.
Follow the two emphasized points.
You can pass a null pointer, NULL, to free() as many times as you want, they are valid calls (just to be ignored).
You cannot pass a pointer which has already been passed to free() once.
Case 1:
Here, after calling free() with the pointer, we're explicitly setting the pointer to NULL. That is why, calling free() with the same pointer variable later, any number of time, is not an issue, at all.
case 2:
C uses pass-by-value for function argument passing. That's why, When wrapped inside a function,
free(pp);
works as expected, (it passes the required pointer to free()) but
pp = NULL;
is local to the function and that change is not reflected to the caller. Thereby, calling the function again causes double free, as now,
the pointer has already been passed to free()
the assigned NULL is not reflected to the caller, hence the pointer is not set to NULL
in the next call, we're passing already-free()d pointer again.
As already mentioned, this invokes undefined behavior.
Solution: You need to pass a pointer to the pointer as the argument of the called function safefree() and from the called function, you can set the pointer value to NULL to get it reflected in the caller. Something like
void safefree(void ** ptrToPtr)
{
free(*ptrToPtr);
*ptrToPtr= NULL;
}
and calling like
safefree (&ptrToBeFreed);
will do the job (mind the types there, anyways).
Aside from Jonathan's remark, if you do something that results in undefined behavior (free the pointer again), it results in undefined behavior (errors, crashes).
Doing the same thing in different contexts does not necessarily result in the same undefined behavior, it depends on implementation details; they are typically only known to the compiler developer, so they seem 'random' from the outside. Nothing much can be learned by analyzing random undefined behavior. It could for example be that the compile time affects the result..., or the spelling of the directory you work in... anything.
This question already has answers here:
Why do I get different results when I dereference a pointer after freeing it?
(7 answers)
Closed 9 years ago.
Below is the code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p=(int *)malloc(sizeof(int));
*p=5;
printf("Before freeing=%p\n",p);
printf("Value of p=%d\n",*p);
//making it dangling pointer
free(p);
printf("After freeing =%p\n",p);
printf("Value of p=%d\n",*p);
return 0;
}
Below is the output:
Before freeing=0x1485010
Value of p=5
After freeing =0x1485010
Value of p=0
After freeing the pointer, dereferencing gives the output "0"(zero).
Below is another code that also gives '0'
include <stdio.h>
#include <stdlib.h>
int main()
{
int *p;
p=(int *)malloc(sizeof(int));
printf("Before freeing=%p\n",(void *)p);
printf("Value of p=%d\n",*p);
return 0;
}
In this i have not freed the memory , just allocated it , still it gives '0' .
Is it like the default value of every uninitialized pointer is '0'??
why is it so ?
Don't rely on this, it's undefined behaviour. free() doesn't have to set the pointer to zero, this is just what your current implementation is doing for you. If you want to be 100% sure, regardless of your compiler, platform, etc. set your pointer to NULL after freeing it.
This is simply undefined behavior if we look at the C99 draft standard Annex J.2 which covers undefined behavior says:
The behavior is undefined in the following circumstances:
and included the following bullet:
The value of a pointer that refers to space deallocated by a call to the free or
realloc function is used (7.20.3).
Setting a pointer to NULL after free'ing is usually a good idea and you can find a good discussion here on that topic.
Dereferencing an invalid pointer leads to undefined results per spec. It's not guaranteed to fail.
While the answers "it doesn't matter, it is UB" are in general sufficient, one might be curious why the value changes. Curiosity is (IMHO) a valid reason to know the reason of why something happens.
It depends on the memory management which might decide to store addresses of the "next free block" or whatever in a freed memory area.
So what you observe is probably an action of the memory management.
For example, the memory management MIGHT be implemented in that way that it manages two linked lists and an upper pointer. One linked list contains the allocated memory chunks, pointing maybe 8 or 16 bytes before the "really usable" memory, and the other linked list points to the first free chunk, which in turn contains a pointer to the next one. The memory above the upper pointer is considered as free.
If you free the first memory block, the free list pointer points to it, and its first pointer sized data is zeroed, meaning that there is no other freed block. And there is your reason why the memory is zeroed out.
It is nice to know that things like these exist and how they work, but refrain the temptation to make use of that knowledge in production programs. One day they may fall onto your feet...
What happens if you try to free a memory which is not allocated using malloc/calloc?
Here is what I mean :
void main()
{
int temp = 0;
int *ptr = &temp;
free(ptr);
}
I thought free() would return some error code but free() does not have a return value.
If you call free() on the pointer which wasn't allocated before, it will trigger undefined behavior.
From Linux man pages:
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
To add to Malcolm's answer: This is undefined behavior by ISO/IEC 9899:1999, 7.20.3.2:
Otherwise, if the argument does not match a pointer earlier returned by the
calloc, malloc, or realloc function [...] the behavior is undefined.
See the draft standard here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf.
I extended the above code a bit:
#include <stdio.h>
#include <stdlib.h>
void main()
{
int temp = 0;
int *ptr = &temp;
printf("Before: %0X\n", ptr);
free(ptr);
printf("After: %0X\n", ptr);
getchar();
}
If this code is compiled by Visual Studio 2010, in Debug configuration, calling free initiates a "Debug Assertion failed" message. This error message comes from dbgheap.c:
/*
* If this ASSERT fails, a bad pointer has been passed in. It may be
* totally bogus, or it may have been allocated from another heap.
* The pointer MUST come from the 'local' heap.
*/
_ASSERTE(_CrtIsValidHeapPointer(pUserData));
Compiling with MinGW-GCC, the resulting exe runs without error (the "After: ..." line shows the same value for ptr as the "Before: ..." line).
All hell will break loose.
Which means:
If you are lucky, your program will error out and terminate.
If you are not lucky, some attacker will execute arbitrary code using your program (free() will usually try to insert your newly freed "chunk" of memory into some data structure, which usually involves some writes at locations determined by values at/near the pointer you passed).
Anything between these two extremes. Not terminating in error should be considered worse than terminating in error.
In addition to the answers by Malcom and undur_gongor, C on Windows with Visual Studio is the same. The pertinent section from MSDN's description is found here:
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.
Tried the following code :
#include<stdio.h>
int main()
{
int *p,*q;
p = (int *)malloc(sizeof(int));
*p =10;
q = p;
printf("%u \n",p);
printf("%u \n",q);
free(p);
printf("%u \n",p);
return 0;
}
The output got is as follows :
[root#lnxdesk Tazim]# ./a.out
154804232
154804232
154804232
Why is that address inside p is still printed even if I have done free(p);?
What has free(p) done then?
I want to understand the concept of free/malloc clearly. Any help will be valuable.
free() only frees the memory on the heap. It does not change the value of your pointer. If you tried to print the memory pointed by your pointer, you'll probably get some kind of garbage.
Also, when you called free, you gave it the pointer, not the address to your pointer, so free can't change your pointer...
That's undefined behavior - once you've freed the pointer the address stored becomes invalid and you can't do anything with it - not only you can't dereference it, but you can't even printf() the pointer value.
You are printing the pointers, i.e. the address of the memory zones allocated for you ints. Freeing a memory zone with free does not set the pointer's address to 0x00 as I think you expect.
It just tells the OS that the memory zone is available again for future re-use.
If you were printing *p after free(p), you would have problems.
malloc() and its ilk reserve space in a memory storage area called the "heap" and return a pointer to that reserved area. So in your sample above p is given a pointer to, probably, a four-byte memory region that has been reserved for its use (whose address happens to be 154804232 this time around). When you do *p = 10 you are now placing the integer value 10 into the memory pointed to. When you do q = p you're now making q point to the same chunk of reserved heap memory.
free() and its ilk just unreserve the memory. When you call free() you're saying "I'm not going to use this memory anymore". All free() does is tell the memory management system that the block of memory is now available for use once again. It emphatically does not change your pointer. It just signals that the block of memory is available. After that it is up to you to ensure that you do not use that pointer again.
If you do use that pointer again it may work fine. Once. Or twice. Or a thousand times. It'll work fine, basically, until you use it after someone else claims that memory block you've said is free and does something with it. When that transpires, Bad Things Happen<tm>. Please don't make bad things happen.
Remember : a pointer is nothing but an address. Before, after your malloc, or free, it'll give you the same result. The only thing that malloc() does is reserve space at this address. The only thing that free does is release it (most probably, mark this address as usable to store other things, "cleaning" would be time consuming).
This is why putting your pointer to NULL after a free is a good idea ; because you can be sure if the pointer is connected to something or not.
free does not reassign the pointer to point to something else. In fact, the C standard
does not mention anything be done with the pointer. This is all it says in the description:
The free function causes the space
pointed to by ptr to be deallocated,
that is, made available for further
allocation. If ptr is a null pointer,
no action occurs. Otherwise, if the
argument does not match a pointer
earlier returned by the calloc,
malloc, or realloc function, or if the
space has been deallocated by a call
to free or realloc, the behavior is
undefined