Is it okay to free multiple dynamically allocated memories at once? - c

During my school assignments, I just got curious if it really frees as I expect.
#include "stdio.h"
#include "stdlib.h"
void main(){
int* menu1 = (int*)malloc(sizeof(int));
int* menu2 = (int*)malloc(sizeof(int));
int* menu3 = (int*)malloc(sizeof(int));
int* menu4 = (int*)malloc(sizeof(int));
int* menu5 = (int*)malloc(sizeof(int));
free(menu1,menu2,menu3,menu4,menu5);
system("pause");
}
It still runs in VS2017, but I'm not sure that it's freed correctly.

for each pointer you have, you allocated memory separately. By memory allocation, the system allocates a bit more that requested in order to safe some control information which should be used for different internal purposes and also later for deallocation.
Since each allocated memory knows only about itself and not about other allocated pieces of memory, you cannot free all together.
The function free expects only one argument (one pointer). Please see 7.22.3.3 in C standard.
GCC doesn't compile this code.

No.
https://linux.die.net/man/3/free
void free(void *ptr);
I code does not compile:
error: too many arguments to function ‘free’
free(menu1,menu2,menu3,menu4,menu5);

The code as is, will not compile:
free(menu1,menu2,menu3,menu4,menu5); /* error: too many arguments to function 'free' */
The function free is defined in header <stdlib.h> and takes only one parameter:
void free( void* ptr );
Parameters:
`ptr` - pointer to the memory to deallocate
Return value:
(none)
Function deallocates the space previously allocated by malloc(), calloc(), aligned_alloc, (since C11) or realloc().
If ptr is a null pointer, the function does nothing.
References:
C11 standard (ISO/IEC 9899:2011):
7.22.3.3 The free function (p: 348)
C99 standard (ISO/IEC 9899:1999):
7.20.3.2 The free function (p: 313)
C89/C90 standard (ISO/IEC 9899:1990):
4.10.3.2 The free function

Your code does not compile, because the function free() expects one argument, but you passed more than that; 5 to be exact.
You could make it compile by enclosing the arguments in parentheses:
free((menu1, menu2, menu3, menu4, menu5));
This allows all the arguments to be evaluated by using the comma operator, but only the last one will be used by the function free(). That is, only menu5 will be freed, and the rest won't.
You must call free() on each argument separately to release memory appropriately:
free(menu1);
free(menu2);
...
free(menu5);

If this compiles you are using an olde compiler. What you are showing is a common error in C code.
What happens in this case the generated code looks something like this:
PUSH menu5 ; which probably looks more like "menu5(SP)"
PUSH menu4
PUSH menu3
PUSH menu2
PUSH menu1
CALL _free
free () only expects one argument and it finds an argument: menu1. The extra arguments simply get ignored.
What would cause even bigger problems is to not pass enough arguments to a function. In that case the function being called would use random garbage on the stack as the argument. Something like
fprintf (fp)
in rarely executed logging code could give you a crash.

Related

Do I need to/can I free a void pointer in C?

I have a void pointer as a parameter for a function. It is currently pointing to an int. When I try to free it, it returns a bus error. Should I be freeing void pointers? If so, how do I do so?
You have to answer two questions first:
Was it previously allocated with a malloc family function (e.g. calloc)?
Did you inherit ownership of it when making the function call?
If the answer to both of those is "Yes", then it's at your discretion, though presumably you'd do it at the appropriate time and place to avoid "use after free" type bugs.
When you inherit ownership of a pointer you inherit the responsibility for calling free() when you're done using it, or passing on ownership to another part of your code. If you fail in this responsibility you have memory leaks.
As a general rule you should never free() a pointer unless you know with certainty that's what you're supposed to do, and you're allowed to do it.
Some functions return pointers to things that you do not own, and even if you did, they're not valid for free() because they may be offset somehow. Only the original pointer returned from the malloc-type function can be used with free().
For example:
void* getBuffer(size_t size) {
globalBufferOffset += size;
return &globalBuffer[globalBufferOffset];
}
This returns a pointer in the middle of some structure that may or may not be dynamically allocated. You don't own it. You should not call free() on it.
Read the documentation very carefully to understand your responsibilities. You may need to call a special free-type function when you're done with the pointer. You may not. You may need to pay attention to thread safety. There's a lot of things that can be going on here you need to be aware of before making a decision.
If the pointer is allocated by malloc or something like that, you have to free.
Because, the malloc function returns the void * pointer, so YES, you can/need to free this pointer.
There are some cases you should not free, for example, the code below:
#include <stdio.h>
#include <stdlib.h>
int main()
{
void *p1, *p2, *p3;
int x, y;
p1 = &x;
p2 = malloc(sizeof(int));
p3 = malloc(10);
*(int*)p2 = y;
p3 = "abc";
free(p1); // it raises the fault because p1 is not allocated by malloc
free(p2); // it's OK
free(p3); // it raises also the fault because p3 points to string literal
return 0;
}
You need a corresponding delete each new or a free for each malloc.
If you never wrote a new or a malloc you don't need a free.
Some libraries have their own version of new and free. They would also have corresponding methods and hopefully some documentation. Like SDL_CreateRGBSurface and SDL_FreeSurface.

Fail to understand why freeing memory throws an error

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.

Shouldn't free() accept a (void *const) as input arg

I was trying to understand the working of free.
Is it defined in the standards that free() will not change the pointer which it was passed?
In standard C argument passing is by value. So a function cannot change the value of its argument (and this is not specific to free). Every call is a call by value. If inside a function you change some argument only a local copy (e.g. in some machine register) of that argument is changed and the caller does not see any change.
If you want to change something, you'll pass the address of that something as a value and you'll dereference that pointer.
Hence free won't change the pointer you pass to it, but you need to be sure to never use that pointer again. Otherwise, that is undefined behavior. A common style is to code free(ptr), ptr=NULL; (so that any further access thru ptr would crash with a segmentation fault).
In practice, most implementations of the C standard library are marking a free-d zone to be reusable by future malloc. But sometimes (notably when freeing a large memory zone) the memory is released to the kernel (e.g. by munmap(2) on Linux). What really happens to the memory zone is implementation specific.
Read wikipages of C dynamic memory allocation & virtual address space.
Look also inside the source code of some free software C standard library implementation (e.g. most libc on Linux, such as musl-libc or GNU libc...). Compile your code with all warnings & debug info (e.g. gcc -Wall -Wextra -g if using GCC...) then use valgrind to hunt memory leak bugs.
The const storage type tells the compiler that you do not intend to modify a block of memory once allocated (dynamically, or statically). Freeing memory is modifying it.
Whether free changes the input argument or not relevant to the calling code. The calling code still has the pointer. It is similar to passing an int to a function. The called function may change the variable but it is change of the copy, not the original.
void foo(int i)
{
i += 2;
}
void bar()
{
int i = 10;
foo(i);
}
Here, the change made to i in foo does not change the value of i in `bar.
Similarly,
void free(void* ptr)
{
// Do the needful to deallocate
...
ptr = NULL;
}
void test()
{
char* p = malloc(10);
...
free(p);
}
Here, the change made to ptr in free does not change the value of the pointer in test. Hence, it does not make much sense to make the argument of free to be of type void* const.

Query related to free() in 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.

Freeing a character pointer

I have a function which is called multiple times during the program's execution. In said function, I have a dynamic character pointer which I resize numerous times.
My question is: do I need to free this pointer before the end of the function?
void functionName()
{
char *variable = (char *) malloc(0);
//variable is resized with realloc x number of times
//should free be called here?
return;
}
I should also note that I have tried to free the pointer, however, gdb gives me warnings when I do so.
Yes, you have to free it or you'll leak the memory. Your code should look something like this:
void function(void)
{
char *variable = (char *)malloc(0);
variable = realloc(variable, 10);
// do something with new memory
variable = realloc(variable, 20);
// do something with more new memory
free(variable); // clean up
}
Calling malloc(0) is a little weird, I think.
A few points to make:
I can't see how you use realloc() in your code, but if you're using it like this, it's wrong:
variable = realloc(variable, amount);
When it's unable to allocate more memory, realloc() returns NULL but leaves the original pointer unaltered. In the above line, this means that variable is NULL and we've lost access to the memory it pointed to, but that memory hasn't been freed. The correct idiom is this:
void *tmp = realloc(variable, amount);
if(tmp)
{
// success! variable invalid, tmp has new allocated data
variable = tmp;
}
else
{
// failure! variable valid, but same size as before, handle error
}
The reason you should use the second one is because, with realloc(), failure is bad, but is quite recoverable in many situations, unlike malloc() where failure usually means "stop everything and die."
This is a more contentious issue, but it is questionable whether or not you should cast the return value of malloc() and realloc() like you do. Consider:
// functionally identical in C
char *a = malloc(10);
char *b = (char *)malloc(10);
In C++, the cast must be made, because in C++ void * cannot be implicitly converted to another pointer type. (I think this is a language mistake, but it's not my place to judge.) If your code is C++, you should be using new and delete anyway. If your code is C but needs to compile with C++ compilers (for some inane reason), you have no choice but to cast. If you don't need to compile C code with C++ compilers (which is similar to having to run Ruby code in a Python interpreter), continue to the points below, which are why I think you shouldn't cast.
In C89, if a function is used without being declared, it will be implicitly declared as returning an int. If, say, we forgot to #include <stdlib.h> and we called malloc(), the version without a cast would cause a compiler error (implicit casts from int to char * aren't allowed), while the version with the cast would (wrongly) tell the compiler "I know this sounds crazy, but cast it anyway." Most compilers will give you a warning for implicit (or incompatable) declarations of built-in functions like malloc(), but the cast does make it harder to find.
Say you have some data:
float *array = (float *)malloc(10 * sizeof(float));
Later, you discover that you need more precision on your data, and have to make this a double array. In the above line, you need to change no more than 3 different places:
double *array = (double *)malloc(10 * sizeof(double));
If, on the other hand, you had written:
float *array = malloc(10 * sizeof *array);
You would only need to change float to double in 1 place. Furthermore, always using sizeof *obj instead of sizeof(type) and never using casts means that a later call to realloc() can work without any changes, while using casts and explicit type names would require finding anywhere you called realloc and change the casts and sizeofs. Also, if you forget, and do this:
double *array = (float *)malloc(10 * sizeof(float));
On most platforms, array will now only be an array of 5 elements, assuming the alignment isn't off and the compiler doesn't complain that you're assigning a float * to a double *. Some consider the warning the compiler issues to be helpful, as it points out potentially incorrect lines. However, if we avoid sizeof(type) and avoid casting, we can see that the lines won't be incorrect, so having the compiler draw attention to them is wasting time we could be using to program.
From the man pages:
If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
So, I believe the answer is "yes" :).
Yes you need to call free() once to release the block of memory. You do not need to call free for the subsequent reallocs() that you are doing, even if those return a different address/pointer. The memory manager knows that the old block is not needed any longer and will free() it.
You should be able to just call free(variable) at the end. If realloc ever has to move the data in order to resize it, it calls free internally, you do not need to worry about that.
Also, where you initialize variable, you could just set it to NULL instead of calling malloc; realloc will work just like malloc the first time.
Have a look at some of the answers I have given to a couple of questions in relation to memory management:
Why are memory leaks common?
What's the point in malloc(0)?
C String confusion?
Need help in solving segmentation fault.
C stdlib realloc issue?
C: Creating array of strings from delimited strings.
All of the above point out the obvious thing, for every malloc there is a free, if not you have a memory leak, so it is imperative that you free the memory when you are finished with your pointer variable that is mallocd.
Hope this helps,
Best regards,
Tom.
int main(int argc, char *argv[])
{
char *p = malloc(sizeof(argv[1]));
p = argv[1];
printf("%s\n", p);
free(p);
return 0;
}
iam getting the glibc error
hello
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff66be94c6 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f38dca1db96]
./a.out[0x4005ed]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f38dc9c076d]

Resources