Query related to free() in C - c

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.

Related

Freeing a pointer inside a function, and using it in main

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
char* test() {
char* s = "Hello World";
size_t len = strlen(s);
char* t = malloc(sizeof(char)*(len+1));
strcpy(t, s);
free(t);
return t;
};
int main(void) {
printf("%s\n", test());
return 0;
};
I would like to allocate and de-allocate memory inside the function. I tested this code and works, but I am wondering:
Why does this work?
Is it good practice to use the value of a freed pointer in main ?
Once you call free on a pointer, the memory it pointed to is no longer valid. Attempting to use a pointer to freed memory triggers undefined behavior. In this particular case it happened to work, but there's no guarantee of that.
If the function returns allocated memory, it is the responsibility of the caller to free it:
char* test() {
char* s = "Hello World";
size_t len = strlen(s);
char* t = malloc(sizeof(char)*(len+1));
strcpy(t, s);
return t;
};
int main(void) {
char *t = test();
printf("%s\n", t);
free(t);
return 0;
};
malloc reserves memory for use.
free releases that reservation. In general, it does not make the memory go away, it does not change the contents of that memory, and it does not alter the value of the pointer that held the address.
After free(t), the bytes of t still contain the same bit settings they did before the free. Then return t; returns those bits to the caller.
When main passes those bits to printf, printf uses them as the address to get the characters for %s. Since nothing has changed them, they are printed.
That is why you got the behavior you did with this program. However, none of it is guaranteed. Once free was called with t, the memory reservation was gone. Something else in your program could have used that memory. For example, printf might have allocated a buffer for its own internal use, and that could have used the same memory.
For the most part, malloc and free are just methods of coordinating use of memory, so that different parts of your program do not try to use the same memory at the same time for different purposes. When you only have one part of your program using allocated memory, there are no other parts of your program to interfere with that. So the lack of coordination did not cause your program to fail. If you had multiple routines in your program using allocated memory, then attempting to use memory after it has been released is more likely to encounter problems.
Additionally, once the memory has been freed, the compiler may treat a pointer to it as if it has no fixed value. The return t; statement is not required to return any particular value.
It doesn't matter where do you free() a pointer. Once it is free()d, the pointer is not deferrenciable anymore (neither inside nor ouside the function where it was free()d)
The purpose of free() is to return the memory allocated with malloc() so the semantics are that, once you have freed a chunk of memory, it is not anymore usable.
In C, all parameters are passed by value, so free() cannot change the value expression you passed to it, and this is the reason the pointer is not changed into an invalid pointer value (like NULL) but you are advised that no more uses of the pointer can be done without incurring in Undefined Behaviour.
There could be a solution in the design of free() and it is to pass the pointer variable that holds the pointer by address, and so free() would be able to turn the pointer into a NULL. But this not only takes more work to do, but free() doesn't know how many copies you have made of the value malloc() gave to you... so it is impossible to know how many references you have over there to be nullified. That approach makes it impossible to give free() the responsibility of nullifying the reference to the returned memory.
So, if you think that free doesn't turn the pointer into NULL and for some strange reason you can still use the memory returned, don't do it anymore, because you'll be making mistakes.
You are adviced! :)

Malloc'ed memory returned by function is not being freed

Below I am using function input to collect and return a string to function main.
I stored the returned pointer/string in a char* and am using that variable to free the malloced memory after using it.
However, it appears that the malloced memory is still usable after my free call.
char* input();
const int MAX = 100;
int main() {
while(1) {
char * input_function_pointer = input();
printf("%p", &input_function_pointer);
puts(input_function_pointer);
free(input_function_pointer);
puts("_______");
printf("%p", &input_function_pointer);
puts(input_function_pointer);
puts("_______");
}
return 0;
}
char* input() {
char * str = malloc(MAX);
printf( "Enter a value :");
fgets( str, MAX, stdin );
return str;
}
Freeing memory does not enforce erasing its content (depends on compiler option, mostly debugging turned on) and nothing prevents you from accessing that space. You're in Undefined Behavior accessing what is called a "dangling pointer": you will probably still see the same content right after you've freed it, probably not after other malloc are called ... or crash.
Freeing memory is merely marking that space as available for allocation, not preventing further read (or write) access. That's (also) why C is considered "low level".
There are no guarantees what will happen if you try to access a chunk of memory after freeing it. This is undefined behavior, which just happens to work in this case, with your specific compiler.
7.22.3.3 The free function c11
The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation
Dereferencing dangling pointer invokes undefined behavior.
free does not amend the content of the freed memory. It does not also change the pointer.
The pointer containing the reference to the freed memory is called dangling pointer and dereferencing it (as you do in your program) is an Undefined Behaviour

Is freeing an allocated pointer with a null value necessary?

I wonder, if I have the following code:
var = (double *)calloc(vars_ptr->amount, sizeof(double));
if (var == NULL) {
printf("ERROR: Problem in memory allocation");
exit(1);
}
Is it possible there will be a memory leak? I mean exiting without freeing, since it indicates the memory allocation process didn't take place.
If no memory was allocated, you don't have to free anything.
That said, free(NULL) isn't harmful. It just doesn't do anything.
That said, there is no point in freeing memory just before you're exiting anyway. That's not a memory leak; a leak would be not freeing memory and keeping running.
No, this
var = (double*)calloc(vars_ptr->amount, sizeof(double));
if (var == NULL){
printf("ERROR: Problem in memory allocation");
/* #TODO proper error handling i.e use error no & stderr */
exit(1);
}
doesn't causes memory leak, as if call to calloc() fails i.e memory allocation was failed i.e you don't have to call free().
From C standard
7.20.3.2 The free function
#include <stdlib.h>
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.
When you call malloc or calloc, and the call returns NULL, that means that nothing has been allocated, so nothing has to be freed, and there's no memory leak.
The case you have to worry about concerns realloc:
newp = realloc(oldp, newsize);
If realloc returns NULL, then oldp still points to the old memory (if any). If you were to write
p = realloc(p, newsize);
this would be a memory leak waiting to happen, the first time realloc failed. (That is, p would contain NULL, and the old, still-valid pointer would be lost.)
If the returned pointer is equal to NULL then this means that the memory was not allocated.
From the description of the function calloc (C11 Standard)
3 The calloc function returns either a null pointer or a pointer to
the allocated space.
You may call free for a null-pointer though this does not have an effect.
On the other hand, you may require a memory of zero size. In this case if the returned pointer is not equal to NULL you have to call free to free the allocated memory.
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *p = calloc( 0, sizeof( int ) );
if ( p != NULL )
{
printf( "p = %p\n", ( void * )p );
}
free( p );
return 0;
}
Using an inline compiler its output
p = 0x55efd9c81260
That is though the required size of memory is equal to 0 nevertheless the system allocated memory that needs to be freed.
Your question is a little confusing:
If you are asking whether you should call free(var) before exiting the program, it is obviously not necessary since var == NULL when this memory allocation failed. There is nothing to free in var. Calling free(var) is allowed, but will do nothing.
If you are asking whether you should free other memory blocks allocated by your program before exiting it on a fatal error for this particular allocation attempt, it is not necessary either because all memory allocated by the OS to the program is released upon exit.
Other system resources such as open files, locks, semaphores... should be released automatically as well but you might still leave the environment in an inconsistent state by exiting the program abruptly like that. For example you might leave some files with inconsistent contents, undeleted temporary files, pending network transactions, inconsistent database updates...
the code you uploaded allocates memory, not freeing it.
according to the info at http://www.cplusplus.com/reference/cstdlib/calloc/ and
https://www.tutorialspoint.com/c_standard_library/c_function_calloc) - calloc returns NULL if the function failed to allocate memory from the OS. thus, it's a good practice to check the pointer after the function call, in order to avoi.
I'd say that if the function fails, either you're trying to allocate way too much memory, or that a memory leak already has occured, so I wouldn't worry about exiting the code after failure - it's probably for the best.

Free causes a error : free(): invalid pointer: 0x0000000001d04018

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.

C++ Allocate and free memory in function

Consider the following code (building with g++):
#include <stdlib.h>
#include <stdio.h>
typedef struct {
int a;
int b;
char c;
} memstr_t;
memstr_t *ptt_backup;
void mmm(memstr_t*& ptt)
{
ptt = (memstr_t *)calloc(15, sizeof(memstr_t));
ptt[0].a = 1;
ptt[0].b = 2;
ptt[0].c = 'c';
ptt_backup = ptt;
}
void fff()
{
free(ptt_backup);
}
int main(int argc, char *argv[])
{
memstr_t *ptt;
mmm(ptt);
printf("%d %d %c\n", ptt[0].a, ptt[0].b, ptt[0].c);
getchar();
//fff();
free(ptt); // same as fff()?
printf("%d %d %c\n", ptt[0].a, ptt[0].b, ptt[0].c); //why works?
getchar();
return 0;
}
I don't understand:
1) Why I'm not getting segfault on the second print since I free the memory? I'm still getting the values which I assigned in mmm()
2) Are free() and fff() doing the same thing?
1) Dereferencing free'd memory can do anything. It may be there, it may not, it is undefined behaviour and could do anything, including faxing your cat.
2) Yes, free() and fff() are doing the same thing as they both point to the same memory location.
Second print uses pointer that is no longer valid, that makes behavior undefined. Whatever can happen, including what makes you believe it "works", and any other time it could be something completely else. DON'T DO THAT!
2: in this code fragment they have the same effect.
calloc allocates memory and returns a pointer to the allocated memory.
In mmm you assign ptt to ptt_backup. Now both of them point to the same place. (Just because I have a name and a nickname , that doesn't make two copies of me. I am a single person accessible via two different names)
In fff you are freeing ptt_backup (read that as freeing the memory pointed by ptt_backup) which is also the one pointed by ptt.It means the memory is not available for you to use now. It can still retain values but its undefined to rely on it. See this nice answer,
Can a local variable's memory be accessed outside its scope?
printf("%d %d %c\n", ptt[0].a, ptt[0].b, ptt[0].c); may not always work.
Then when you do free(ptt) (read that as freeing the memory pointed by ptt) which is already deleted by fff, it is undefined behaviour as stated,
The free() function shall cause the space pointed to by ptr to be
deallocated; that is, made available for further allocation. If ptr is
a null pointer, no action shall occur. Otherwise, if the argument does
not match a pointer earlier returned by the calloc(), malloc(), [ADV]
posix_memalign(), realloc(), or [XSI] strdup() function, or if
the space has been deallocated by a call to free() or realloc(), the
behavior is undefined.
Using a memory pointer that points to freed memory leads to undefined behavior. This means that a segfault doesn't necessarily happen, but is possible. Therefore, you never should dereference freed memory.
They (fff and free) are the same thing in this context, because they point to the same address.
You never allocate memory for ptt_backup! You're in undefined behaviour land; anything could happen in fff()

Resources