Trying to use free() to understand how it works - c

To understand the usage of free in the C programming language I tried running this code on Ubuntu, but on running the EXE file I am receiving a SIGABRT error. Why is the program not exiting normally?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ret;
int *ptr;
ptr = (int *)malloc(sizeof(int)*10);
free(ptr);
ptr = &ret;
free(ptr);
return 0;
}

Attempting to free a pointer you didn't get from malloc (or one of its friends) causes undefined behaviour. Your second free(ptr) call attempts just that.
From the C spec, §7.22.3.3 The free function, paragraph 2:
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.

While all the the undefined behavior answers are correct, seeing an implementation might be more helpful.
I think a very good reference to this is K&R C malloc. An explanation of how it works is in "The C Programming Langugage", Chapter 8.7.
Remember when looking at code from standard library functions in C that they have an implementation and a specification, where the implementation might have reproducible behavior that is not required by its specification.
Essentially almost all malloc implementations have a free list where they manage free memory regions in a list (or multiple lists). The free list is often handled in a way, that calling free on a memory region multiple times will put this list in an incorrect state.
Also malicious behavior can be invoked when data structures are purposefully crafted. Phrack has a dated article on how to invoke code execution when passing invalid memory to free while corrupting the freelist.
Other malloc implementations might also be worth looking at (this is an incomplete list of allocation libraries).

ptr = &ret;
free(ptr);
is the same as:
free(&ret);
ret resides on the stack, not on the heap. Attempting to free() memory that was not allocated (with malloc(), etc.) on the heap will cause undefined behavior.

The function free() only works for the memory that has been allocated on heap by malloc(). Not for the static allocation, because static allocations are automatically handled. Here is the mistake:
int ret;
ptr = &ret;
free(ptr);
You can't do this because the memory for ret is not allocated on the heap. It's in the stack and only the memory of the heap should be freed.

Your second free(ptr) is causing undefined behavior as you are attempting to free a pointer which you didn't allocate. Also note that static allocations are automatically reclaimed, so you don't require them to free it.

ptr = &ret;
free(ptr);
Here you are trying to free the local storage stack variable's memory. As per rule you should not free it. When the main() exits all local storage memory on stack always get free.
Free only works with Heap allocation memory.

There are three areas where variables may be created in a c or c++ program.
global or static variables are at fixed locations in the executable binary file.
automatic variables outside of static scope are on the stack
malloc'ed or calloc'ed variables are on the heap.
free() is the function that releases previously allocated memory on the heap. A pointer to memory on the heap is returned by malloc or similar functions. The only way to read or write that memory is via the pointer. A pointer is an address, and a pointer* is the content pointed to at that address.
In the example shown, there are two variables, defined in Main, and effectively static, and the returned value from Main, which is on the stack. Using the miniumum int, 16 bits, here's a possible memory map. In this map, the instructions start at 0, the stack starts at some non-zero value, (beginning of stack - bos) and grows by incrementing, and a heap starts at the maximum address (...FFFF, aka -1) and grows by decrememeting:
(Remember, MIN_INT is -32768, MAX_INT is 32767... the spec guarantees only 16 bits, signed)
Each byte has an address which is 'n' bits wide - 16, 32 or 64 bits, typically
-1. (start of heap, for example, 16 bit addr: 0xFFFF, 32 bit addr: 0xFFFFFFFF or 64 bit addr: 0xFFFFFFFFFFFFFFFF)
-2. (1st location down from beginning of heap. 0x...FFFE) ptr[ 9 ], at one time
-3. (2nd location down from beginning of heap. 0x...FFFD)
-4. (3rd location down from beginning of heap. 0x...FFFC) ptr[ 8 ], at one time
[snip]
-17. (16th location down from beginning of heap. 0x...FFEF)
-18. (17th location down from beginning of heap. 0x...FFEE) ptr[ 1 ], at one time
-19. (18th location down from beginning of heap. 0x...FFED)
-20 (19th location down from beginning of heap. 0x...FFEC) ptr[ 0 ], at one time
-21. (top of heap, 10 X 16 bit ints down from beginning of heap. 0x...FFEB), at one time
:
A very large range of address on 32 or 64 bit machines...
:
tos: ( Top of stack 0x...tos )
bos + ( sizeof( int ) - 1) End of int returned from Main()
bos: (beginning of stack: above static data ) Start of int returned from Mail()
togs: (top of global/static) End of "ptr"
: (size of a pointer is width of address bus... whatever it takes)
togs-(n-1): (top of global/static - (sizeof( int* ) - 1)) start of "ptr"
(togs-n) : End of "ret"
(togs-n)-1: start of "ret"
(any global stuff the compiler adds for itself, the debugger, etc.)
(end of program code)
(start of program code)
(top of non-program code)
0 (start of non-program code, 0x...0000 )
At run-time, "ptr" and "ret" are probably both start at '0', since they're fixed, static, values, read out of the file the executable binary comes from.
As the program runs, the value of "ptr" changes, first, to point into the heap, at the malloc'ed array of 10 ints: "0x...FFEC"
The call to free() doesn't change the value of ptr, its still "0x...FFEC"
Free'ing "0x...FFEC" is legit and runs without anything funny.
The assignment "ptr = &ret" sets a new value into "ptr", "(togs-n)-1", the start of "ret".
Free'ing "(togs-n)-1" causes an immediate crash because "free" checks the value of "(togs-n)-1" and it is NOT in the valid range for a heap address.
"ret" remains blank, its never set, but since its global/static, it remains at whatever it was when the linker wrote it to disk.

Related

Calling free on a pointer to an element of an array declared dynamically

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.

Correct usage of free() function in C

I am new in C programming language so can you tell me if this is correct way to do.
for example:
program points on buffer and i use that pointer as parameter in free() function. So, what problems can this function cause ?
You should call free only on pointers which have been assigned memory returned by malloc, calloc, or realloc.
char* ptr = malloc(10);
// use memory pointed by ptr
// e.g., strcpy(ptr,"hello");
free(ptr); // free memory pointed by ptr when you don't need it anymore
Things to keep in mind:
Never free memory twice. This can happen for example if you call free on ptr twice and value of ptr wasn't changed since first call to free. Or you have two (or more) different pointers pointing to same memory: if you call free on one, you are not allowed to call free on other pointers now too.
When you free a pointer you are not even allowed to read its value; e.g., if (ptr) not allowed after freeing unless you initialize ptr to a new value
You should not dereference freed pointer
Passing null pointer to free is fine, no operation is performed.
Think that the computer has a whole bunch of memory not (yet) used by your program. Now you need some more memory and you ask your computer to give you some more (for example, a large buffer). Once you are done with it, you want to return it to the computer.
This memory is called the heap. You ask for memory by calling malloc() and you return it by calling free();
char *buffer;
buffer = malloc(512); // ask for 512 bytes of memory
if (buffer==NULL) return -1; // if no more memory available
...
free(buffer); // return the memory again
free() function is used to deallocate memory used by one program and move it back to available memory area so that other operating system processes can use that memory location. Also free function takes any type of pointer that points to that memory location.
For example:
int a = 10; // suppose 2 byte is allocated ie location 1000 and 1001
Now this 2 byte of memory belongs to specific problem; hence OS will not give this memory location to another process (memory is now allocated memory not available memory)
int *ptr =&a;
/*ptr is pointer variable pointing to 1000
as it is int pointer therefore ptr++ will move pointer to 1002*/
Now if we do free(ptr), it will check the pointer type and depending on type free function deallocate memory in this case 2 bytes starting from 1000.
Now interesting point is your data will be there until OS allocates this memory to some other process and that process overwrites it.
Also ptr is pointing to 1000 even after free() function but that memory location does not belong to our program hence ptr pointer has given new name DANGLING POINTER.
*ptr may or may not give the same value therefore it is better to make ptr =null.
From the man page of free() function:
The free() function frees the memory space pointed to by a pointer ptr which must have been returned by a pre‐
vious 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.
You have to use the free() function when you are allocating the memory dynamically.
If you are using that as a static variable then it may lead to unintended behavior.
char *c=malloc(100);//allocating the 100 bytes of memory for a pointer variable c.
Here after usage of that varaible you can free that allocated memory,
free(c);
If you are declared a variable like this,
char c= malloc(100);// It is illegeal. And c will have a memory in stack.
If you free this variable,
free(c);//it will lead to system crash. Because your freeing the memory which is in stack memory.

Freeing portions of dynamically allocated blocks?

I was curious whether there exists a dynamic memory allocation system that allows the programmer to free part of an allocated block.
For example:
char* a = malloc (40);
//b points to the split second half of the block, or to NULL if it's beyond the end
//a points to a area of 10 bytes
b = partial_free (a+10, /*size*/ 10)
Thoughts on why this is wise/unwise/difficult? Ways to do this?
Seems to me like it could be useful.
Thanks!
=====edit=====
after some research, it seems that the bootmem allocator for the linux kernel allows something similar to this operation with the bootmem_free call. So, I'm curious -- why is it that the bootmem allocator allows this, but ANSI C does not?
No there is no such function which allows parital freeing of memory.
You could however use realloc() to resize memory.
From the c standard:
7.22.3.5 The realloc function
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
There is no ready-made function for this, but doing this isn't impossible. Firstly, there is realloc() . realloc takes a pointer to a block of memory and resizes the allocation to the size specified.
Now, if you have allocated some memory:
char * tmp = malloc(2048);
and you intend to deallocate the first, 1 K of memory, you may do:
tmp = realloc(foo, 2048-1024);
However, the problem in this case is that you cannot be certain that tmp will remain unchanged. Since, the function might just deallocate the entire 2K memory and move it elsewhere.
Now I'm not sure about the exact implementation of realloc, but from what I understand, the code:
myptr = malloc( x - y );
actually mallocs a new memory buffer of size x-y, then it copies the bytes that fit using memcpy and finally frees the original allocated memory.
This may create some potential problems. For example, the new reallocated memory may be located at a different address, so any past pointers you may have may become invalidated. Resulting in undefined runtime errors, segmentation faults and general debugging hell. So I would try to avoid resorting to this.
Firstly, I cannot think of any situation where you would be likely to need such a thing (when there exists realloc to increase/decrease the memory as mentioned in the answers).
I would like to add another thing. In whatever implementations I have seen of the malloc subsystem (which I admit is not a lot), malloc and free are implemented to be dependent on something called as the prefix byte(s). So whatever address is returned to you by malloc, internally the malloc subsystem will allocate some additional byte(s) of memory prior to the address returned to you, to store sanity check information which includes number of allocated bytes and possible what allocation policy you use (if your OS supports multiple mem allocation policies) etc. When you say something like free (x bytes), the malloc subsystem goes back to peek back into the prefix byte to sanity check and only if it finds the prefix in place does the free successfully happen. Therefore, it will not allow you to free some number of blocks starting in between.

Instead of just using free() and having the pointer pointing some new block, how to really empty the previously-pointed-at memory block?

I am trying to free dynamically allocated memory using free(), but I found that what it does is to have the argument pointer point to some new location, and leaving the previously-pointed-at location as it was, the memory is not cleared. And if I use malloc again, the pointer may point to this messy block, and it's already filled with garbage, which is really annoying..
I'm kinda new to C and I think delete[] in c++ doesn't have this problem. Any advise?
Thanks
By free the memory is just released from use. It is released from being allocated to you. it is not explicitly cleared. Some old contents might be present at those memory locations.
To avoid this, there are two solutions.
Solution 1:
You will need to do a memset after allocating memory using malloc.
Code Example:
unsigned int len = 20; // len is the length of boo
char* bar = 0;
bar= (char *)malloc(len);
memset(bar, 0, len);
Solution 2:
Or use, calloc() which initiliazes memory to 0 by default.
Code Example:
int *pData = 0;
int i = 10;
pData = (int*) calloc (i,sizeof(int));
I think delete[] in c++ doesn't have this problem.
No
It behaves exactly this same way. Unless you explicitly set the pointer to 0 the delete'd pointer will not be pointing to 0. So do always set the pointer to 0 after you delete it.
When should you use malloc over calloc or vice versa?
Since calloc sets the allocated memory to 0 this may take a little time, so you may probably want to use malloc() if that performance is an issue.(Ofcourse One most profile their usage to see if this really is a problem)
If initializing the memory is more important, use calloc() as it does that explicitly for you.
Also, some OS like Linux have an Lazy Allocation memory model wherein the returned memory address is a virtual address and the actual allocation only happens at run-time. The OS assumes that it will be able to provide this allocation at Run-Time.
The memory allocated by malloc is not backed by real memory until the program actually touches it.
While, since calloc initializes the memory to 0 you can be assured that the OS has already backed the allocation with actual RAM (or swap).
How about realloc?
Yes, similar behavior to malloc.
Excerpt From the documentation:
void * realloc ( void * ptr, size_t size );
Reallocate memory block
The size of the memory block pointed to by the ptr parameter is changed to the size bytes, expanding or reducing the amount of memory available in the block.
The function may move the memory block to a new location, in which case the new location is returned. The content of the memory block is preserved up to the lesser of the new and old sizes, even if the block is moved.If the new size is larger, the value of the newly allocated portion is indeterminate.
In case that ptr is NULL, the function behaves exactly as malloc, assigning a new block of size bytes and returning a pointer to the beginning of it.
In case that the size is 0, the memory previously allocated in ptr is deallocated as if a call to free was made, and a NULL pointer is returned.
You can use calloc( ) instead of malloc( ) to clear the allocated memory to zero.
Why is having newly allocated memory filled with garbage "really annoying"? If you allocate memory, presumably it's because you're going to use it for something -- which means you have to store some meaningful value into it before attempting to read it. In most cases, in well-written code, there's no reason to care what's in newly allocated memory.
If you happen to have a requirement for a newly allocated block of memory you can call memset after calling malloc, or you can use calloc instead of malloc. But consider carefully whether there's any real advantage in doing so. If you're actually going to use those all-bits-zero values (i.e., if all-bits-zero happens to be the "meaningful value" I mentioned above), go ahead and clear the block. (But keep in mind that the language doesn't guarantee that either a null pointer or a floating-point 0.0 is represented as all-bits-zero, though it is in most implementations they are.)
And free() doesn't "have the argument pointer point to some new location". free(ptr) causes the memory pointed to by ptr to be made available for future allocation. It doesn't change the contents of the pointer object ptr itself (though the address stored in ptr does become invalid).

Allocated memory address clash

i don't understand how this happen. This is portion of my code..
int isGoal(Node *node, int startNode){
int i;
.
.
}
When i debug this using gdb i found out that 'i' was allocated at the memory address that have been previously allocated.
(gdb)print &node->path->next
$26 = (struct intNode **) 0xffbff2f0
(gdb) print &i
$22 = (int *) 0xffbff2f0
node->path->next has been already defined outside this function. But as u can see they share the same address which at some point make the pointer point to another place when the i counter is changed.
I compiled it using gcc on solaris platform
Any helps would be really appreciated..
The memory for i is taken from the stack, or what in C is sometimes called "automatic storage."
The contents of memory allocated from the stack are no longer valid after the function declaring that storage has returned. For example, your isGoal() function allocates stack storage for the variable i and the storage exists only until the point in time when isGoal() returns.
The reason you see the address of i, &i has already existed during your program is that the stack memory area is continually reused. Prior to what you see in gdb, you have stored the address of a stack variable in node->path->next.
To obtain memory which remains valid after the allocating function has returned, you must use malloc() and free() to obtain what is called "dynamic memory" or, sometimes, memory from the "heap."
Two possibilities:
You have compiled with optimizations and this is confusing gdb (for example i could be optimized away, so that it actually hasn't any address)
node->path doesn't point to correctly allocated memory. For example that pointer could have been set to point to an object on the stack that subsequently went out of scope.

Resources