Can we free dynamically allocation memory using realloc? - c

My friend and I had a discussion over freeing dynamically allocated memory. He told that a memory could be freed with realloc(), to which I denied.
Let's consider the below code:
int main()
{
int *p = (int *)malloc(sizeof(int) * 10);
int *q = (int *)malloc(sizeof(int) * 10);
free(p);
p = NULL;
realloc(q, sizeof(int) * 0);
q = NULL;
_getch();
return 0;
}
Let's assume p and q are pointing to address 0x1000 & 0x2000 respectively.
In the above code, p and q are int pointers pointing to dynamically allocated 40 bytes of memory blocks in the RAM. On executing free(p) frees the memory address (0x1000). The freed memory address (0x1000) could be used by an OS again. Then, NULL is assigned to pointer variable p to prevent p of becoming a dangling pointer.
realloc(q, sizeof(int) * 0);
realloc() simply shrinks the memory block pointed by q to zero. But q still points to the same address (0x2000), and that address is not freed. On assigning NULL value to pointer q, q now points to NULL and the address (0x2000) to which q was pointing is not freed and the link to that address (0x2000) is lost. That address (0x2000) cannot be used by OS in the future until the end of the program.
Is my understanding correct?

realloc(, 0) is implementation dependent and not equivalent to free().
That said, you might be lucky:
#include <stdio.h>
#include <malloc.h>
int main() {
char *a;
a = malloc(1024);
printf("a = %08lx\n", a);
free(a);
a = malloc(1024);
printf("a = %08lx\n", a);
realloc(a, 0);
a = malloc(1024);
printf("a = %08lx\n", a);
}
gcc version 6.1.1 20160815 [gcc-6-branch revision 239479] (SUSE Linux)
ldd --version
ldd (GNU libc) 2.23
a = 01dad010
a = 01dad010
a = 01dad010
So the second malloc, after realloc(, 0), "sees" a free block where before was a. I take it to mean that in this instance, realloc duplicates the behaviour of free. DO NOT RELY ON THIS.

realloc(q, sizeof(int) * 0);
is same as
realloc(q, 0);
The C standard in 7.22.3.5 ->2 The realloc function says :
..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.
But it doesn't explicitly specify what would happen if the new size is zero.
But you still have an artist pointer that could be passed to free.
Consider
char *a;
a=malloc(2*sizeof *a);
a=realloc(a,0);
// Note I'm purposely NOT using a temporary variable to store 'realloc' results
// Moreover, above is BAD practice.
free(a); // Is this permitted? YES !! Did we technically free memory above? NO !!
//Compiler will not yell at you for the above, in fact it is legal as per the standard
return 0; // No output for this one
vs
char *a;
a=malloc(2*sizeof *a);
free(a);
//You're not suppose to free(a) again.
free(a);
//Compiler will yell at you for the above.
return 0;
output
double free or corruption (fasttop): 0x0000000000915010
Conclusions
deallocation and freeing are not exactly the same things.
Both realloc and free can deallocate memory, but only free frees the memory.
That said
free(p);
p = NULL;
is the recommended way to free memory. Do check [ this ] answer.

Related

Free uninitiailized pointer in C

If I dynamically allocated a space for a pointer, list this:
int *a = (int*)malloc(sizeof(int));
should I free a when the code is done? Thanks!
I think you have a little misunderstanding related to pointer.
Your title says:
Free uninitialized pointer ...
and your code is
int *a = (int*)malloc(sizeof(int));
The problem with this is that there is no uninitialized pointer in the code. The only pointer in the code is the variable a and it is initialized by the value returned by malloc.
Freeing an uninitialized pointer would be bad - example:
int *a; // a is an uninitialized pointer
free(a); // Real bad - don't do this
but since you actually initialize the pointer then - Yes, you must call free when your are done using the object/memory pointer a points to. It does not matter whether or not the pointed-to object (aka memory) has been assigned a value.
The general rule: For each call of malloc there must be a call of free
(Exception: If your program terminates, you don't need to call free)
int *a = malloc(sizeof(*a));
if (a)
{
/* a is now valid; use it: */
*a = 1 + 2 + 3;
printf("The value calculated is %d\n", *a);
}
/* Variable A is done being used; free the memory. */
free(a); /* If a failed to be allocated, it is NULL, and this call is safe. */
Yes.
If you successfully malloc something is is correct to free it as well.
int *a = (int *) malloc(sizeof int);
if (a != NULL)
{
/* Do whatever you need to do with a */
free(a);
}
else
{
puts("the malloc function failed to allocate an int");
}
int *a = (int*)malloc(sizeof(int));
should I free a when the code is done?
The question should be
Must I free a when the code is done?
And the answer is YES. A malloc must be accompanied by a a free statement.
free(a);

What happened when kfree function called

I am testing kernel module that allocates memory using kmalloc to some variable and memset it's value and free.
Here is the code with zeroisation memory routine.
unsigned char *a = (unsigned char *)kmalloc(256, GFP_KERNEL);
unsigned char *b;
int i;
for(i=0;i<256;i++)
{
a[i]=(unsigned char)i;
}
// print variable a
printk("before zeroisation\n");
for(i=0;i<255;i++)
{
printk("%02x", a[i]);
}
// copy allocated address to variable b
b =a;
memset(a, 0x00, 256);
// print memset to zero
printk("memset variable a\n");
for(i=0;i<255;i++)
{
printk("%02x", b[i]);
}
free(a);
a=NULL;
// print free variable's address
printk("after zeroisation\n");
for(i=0;i<255;i++)
{
printk("%02x", b[i]);
}
and result is
before zeroization
000102030405060708090a0b0c0d0e0f ...
memset variable a
00000000000000000000000000000000 ...
after zeroization
001e7f430088ffff0000000000000000 ...
It seems free of variable makes insert value of something's address in allocated area. 001e7f430088ffff -> ffff8800437f1e00 (in little endian)
Additionaly address of pointer of b is ffff8800437f0800
I know that dynamic memory allocation in heap memory has free-list made of double-linked list.
I think this is related to memory allocation process too.
I want to know the meaning of value 001e7f430088ffff and process of within kfree function.
thanks.
b =a;
Which means both a and b points to same memory. Free any pointer will result in losing the memory from both pointers. and then this memory can contain any garbage value.
free(a);
a=NULL;
Once freed no need to assign NULL. When you free a pointer, it means it is no more pointing to any memory.
So if you need to avoid such behavior
Either don't free pointer a. Just assign it NULL or another memory
Or use memcpy(b, a, sizeof(a)); function to copy values in a. But before that you have to allocate memory to b

what will realloc do to the old pointer [duplicate]

This question already has answers here:
Using realloc to shrink the allocated memory
(5 answers)
Closed 2 years ago.
I have a question about the realloc function. Will the content of old pointer be changed after apply realloc function?
The code is
main () {
int *a, *b, i;
a = calloc(5, sizeof(int));
for (i = 0; i < 5; i++)
a[i] = 1;
for (i = 0; i < 5; i++)
printf("%d", a[i]);
printf("\n%p\n", a);
b = realloc(a, 200000 * sizeof(int));
if(b == NULL)
printf("error\n");
for (i = 0; i < 5; i++)
printf("%d", a[i]);
printf("\n");
for (i = 0; i < 10; i++)
printf("%d", b[i]);
printf("\n%p %p\n", a, b);
}
The output is
11111
0x2558010
00111
1111100000
0x2558010 0x7f29627e6010
Pointer a still point to the same address, but the content is changed.
Pointer a still point to the same address, but the content is changed.
That's because realloc() may first try to increase the size of the block that a points to. However, it can instead allocate a new block, copy the data (or as much of the data as will fit) to the new block, and free the old block. You really shouldn't use a after calling b = realloc(a, 200000 * sizeof(int)) since the realloc call may move the block to a new location, leaving a pointing to memory that is no longer allocated. Use b instead.
The value returned by realloc tells you whether it succeeded or failed.
b = realloc(a, 200000 * sizeof(int));
If it fails, it returns a null pointer, and a still points to the original unmodified chunk of memory (and of course b is a null pointer).
If it succeeds, then b points to a (possibly newly allocated) chunk of memory, and the value of a is indeterminate. If it was able to allocate the new chunk in the same place as the old one (by growing or shrinking the chunk in place), then b will be equal to a -- but testing that, or even referring to the value of a, has undefined behavior. If it has to relocate the chunk, then realloc will have done the equivalent of free(a) after copying the data. In either case, it's probably best to set a to NULL to avoid accidentally referring to its (now indeterminate) value.
Note that realloc can relocate chunk even if the new size is smaller.
A simple realloc implementation should answer your questions:
void * realloc(void * ptr, size_t desired_size) {
size_t allocated_size = _allocated_size_of(ptr);
if (allocated_size < desired_size) {
void * new_ptr = malloc(desired_size);
memcpy(new_ptr, ptr, allocated_size);
free(ptr);
ptr = new_ptr;
}
return ptr;
}
malloc and related functions don't always allocate exactly the desired size. Very often they allocate more than the desired size. There is some hidden data kept up with by the memory allocation functions which allows for a pointer that was allocated by malloc or related functions to be used to look up the memory block size that was allocated. How this is kept up with isn't necessary to understand, but some very simple implementations simply store the size in the space just before the pointer returned *(((size_t)ptr)-1).
If realloc() returns a pointer different from the one you passed in (as it will most of the time), then the pointer you passed in no longer belongs to you, and you have no business knowing or caring what becomes of it. It might change its contents, it might not. But you are no longer allowed to access it, so it can be no concern of yours.
If 'a' points a valid block of memory (from a previous malloc/realloc/calloc), then a realloc call will attempt to provide a block of memory with the new size you requested
The realloc call should be of the form *tmp = realloc (a ...
The return value from realloc must be tested
If it is NULL, realloc was unable to allocate the requested memory, and this leaves 'a' as a valid pointer
You are then responsible for handling any data pointed to by 'a' (save it / discard it) and you are responsible for free ing the memory pointed to by 'a'
If the realloc call was successful make b = tmp and now 'b' is the new pointer to the block of memory - it does not matter whether the start location is the same as 'a' or different. 'a' is no longer a valid memory allocation pointer, although further errors will depend on whether 'a' points to memory owned by your program or not - basically if a == b, 'a' can be accessed without obvious errors.
After a valid *tmp = realloc(a ... & b = tmp;:
1) If the start location of the reallocated memory was unchanged: (a == b)
it will allocate the requested memory
but run it under valgrind and you will see error messages:
Invalid free() / delete / delete[] / realloc()
Address 0x51fc040 is 0 bytes inside a block of size 256 free'd
In this case realloc could not free the memory pointed to by 'a'
and again in this case 'a' can still be accessed as it is a pointer to memory that is allocated to your progam
2) If the start location of the reallocated memory was changed: (a != b)
it will fail and Valgrind shows output like this:
address of a: 0x1e89010
address of b: 0x7f2c5893c010
a after realloc: 0x1e89010
Error in `./test15': realloc(): invalid old size: 0x0000000001e89010
and trying to access 'a' will fail - even trying to print it's value as a pointer fails, presumably because it no longer points to memory owned by the program
In other words, using 'a' after b = realloc(a ... is undefined behaviour.
The above commentary was based on using the following code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *a = NULL, *b = NULL, *c = NULL;
/* initial allocation */
a = malloc(256);
if( a == NULL) return (1);
printf("address of a: %p\n", a);
/* reallocation 'b' MAY be same as 'a' - try much larger allocations */
void *tmp = realloc(a, 512);
if ( !tmp ) {
free(a);
return (1);
} else {
b = tmp;
}
printf("address of b: %p\n", b);
/* see what 'a' is now - this MAY crash the program*/
printf("a after realloc: %p\n", a);
/* 'a' may not be a valid pointer - try using it for another realloc */
c = realloc(a, 256);
/* Valgrind shows that memory could not be free'd or 'a' was not valid allocated memory */
printf("return value of c: %p\n", c);
if (c != NULL) {
free(c);
printf("'c' allocated\n");
} else {
free(b);
printf("'c' not allocated\n");
}
return 0;
}
Reading the man page is key here, but the TLDR is if there isn't enough memory to enlarge at the back end of the previous block, it will get a new block of memory, copy the old data into it, and return the address of the new block. The old address should not be used, and most typical realloc statement looks like this
a = realloc(a, 200000 * sizeof(int));
That way you won't accidentally use the possibly wrong old value.
It can't change the address in the pointer, since it is passed by value, so changing it in the function is only changing the local copy.
EDIT : Per Weather Vane's absolutely correct comment, the safer route would be
void * b = realloc(a, 200000 * sizeof(int));
if ( b ) {
a = b;
} else {
;;; /* error handler here */
}

Proper usage of realloc()

From man realloc:The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any kind of variable and may be different from ptr, or NULL if the request fails.
So in this code snippet:
ptr = (int *) malloc(sizeof(int));
ptr1 = (int *) realloc(ptr, count * sizeof(int));
if(ptr1 == NULL){ //reallocated pointer ptr1
printf("Exiting!!\n");
free(ptr);
exit(0);
}else{
free(ptr); //to deallocate the previous memory block pointed by ptr so as not to leave orphaned blocks of memory when ptr=ptr1 executes and ptr moves on to another block
ptr = ptr1; //deallocation using free has been done assuming that ptr and ptr1 do not point to the same address
}
Is it sufficient to just assume that the reallocated pointer points to a different block of memeory and not to the same block.Because if the assumption becomes false and realloc returns the address of the original memory block pointed to by ptr and then free(ptr) executes(for the reason given in the comments) then the memory block would be erased and the program would go nuts.
Should I put in another condition which will compare the equality of ptr and ptr1 and exclude the execution of the free(ptr) statement?
Just don't call free() on your original ptr in the happy path. Essentially realloc() has done that for you.
ptr = malloc(sizeof(int));
ptr1 = realloc(ptr, count * sizeof(int));
if (ptr1 == NULL) // reallocated pointer ptr1
{
printf("\nExiting!!");
free(ptr);
exit(0);
}
else
{
ptr = ptr1; // the reallocation succeeded, we can overwrite our original pointer now
}
Applying fixes as edits, based on the good comments below.
Reading this comp.lang.c question, reveals 3 cases:
"When it is able to, it simply gives you back the same pointer you handed it."
"But if it must go to some other part of memory to find enough contiguous space, it will return a different pointer (and the previous pointer value will become unusable)."
"If realloc cannot find enough space at all, it returns a null pointer, and leaves the previous region allocated."
This can be translated directly to code:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3, clean up then terminate.
free(ptr);
exit(0);
}
else if(tmp == ptr)
{
// Case 1: They point to the same place, so technically we can get away with
// doing nothing.
// Just to be safe, I'll assign NULL to tmp to avoid a dangling pointer.
tmp = NULL;
}
else
{
// Case 2: Now tmp is a different chunk of memory.
ptr = tmp;
tmp = NULL;
}
So, if you think about it, the code you posted is fine (almost). The above code simplifies to:
int* ptr = (int*)malloc(sizeof(int));
int* tmp = (int*)realloc(ptr, count * sizeof(int));
if(tmp == NULL)
{
// Case 3.
free(ptr);
exit(0);
}
else if(ptr != tmp)
{
ptr = tmp;
}
// Eliminate dangling pointer.
tmp = NULL;
Note the extra else if(ptr != tmp), which excludes Case 1, where you wouldn't want to call free(ptr) because ptr and tmp refer to the same location. Also, just for safety, I make sure to assign NULL to tmp to avoid any dangling pointer issues while tmp is in scope.
OP: ... may be different from ptr, or NULL if the request fails.
A: Not always. NULL may be legitimately returned (not a failure), if count is 0.
OP: Is it sufficient to just assume that the reallocated pointer points to a different block of memory and not to the same block.
A: No
OP: Should I put in another condition which will compare the equality of ptr and ptr1 and exclude the execution of the free(ptr) statement?
A: No.
If realloc() returns NULL (and count is not 0), the value of ptr is still valid, pointing to the un-resized data. free(ptr) or not depends on your goals.
If realloc() returns not NULL, do not free(ptr), it is all ready freed.
Example: https://codereview.stackexchange.com/questions/36662/critique-of-realloc-wrapper
#include <assert.h>
#include <stdlib.h>
int ReallocAndTest(char **Buf, size_t NewSize) {
assert(Buf);
void *NewBuf = realloc(*Buf, NewSize);
if ((NewBuf == NULL) && (NewSize > 0)) {
return 1; // return failure
}
*Buf = NewBuf;
return 0;
}
realloc will return the same address to ptr if it have enough space to extend the actual chunk of memory pointed by ptr. Otherwise, it will move the data to the new chunk and free the old chunk. You can not rely on ptr1 being different to ptr. Your program behaves undefined.
If realloc returns another address, it first deallocates the old one so you don't have to do it yourself.
By the way, never cast the return of malloc/realloc :). Your code should be like this:
ptr=malloc(sizeof(int));
ptr=realloc(ptr,count*sizeof(int));
if(ptr==NULL)
{
// error!
printf("\nExiting!!");
// no need to free, the process is exiting :)
exit(0);
}
If realloc moves your data, it will free the old pointer for you behind the scenes. I don't have a copy of the C11 standard, but it is guaranteed in the C99 standard.
You should not free your original pointer if the realloc succeeds. Whether you free that pointer if the realloc fails depends on the needs of your particular application; if you absolutely cannot continue without that additional memory, then this would be a fatal error and you would deallocate any held storage and exit. If, OTOH, you can still continue (perhaps execute a different operation and hope that memory will come available later), the you'd probably want to hold on to that memory and a attempt a another realloc later.
Chapter and verse:
7.22.3.5 The realloc function
Synopsis
1 #include <stdlib.h>
void *realloc(void *ptr, size_t size);
Description
2 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.
3 If ptr is a null pointer, the realloc function behaves like the malloc function for the
specified size. Otherwise, if ptr does not match a pointer earlier returned by a memory
management function, or if the space has been deallocated by a call to the free or
realloc function, the behavior is undefined. If memory for the new object cannot be
allocated, the old object is not deallocated and its value is unchanged.
Returns
4 The realloc function returns a pointer to the new object (which may have the same
value as a pointer to the old object), or a null pointer if the new object could not be
allocated.
Emphasis added. Note clause 4; the returned pointer may be the same as your original pointer.

Two pointers are pointing to same memory address, how to avoid memory leak in case freeing of these two happens at independence place?

int *a = malloc(40);
int *b;
b=a;
if( *some conditions* )
free(a);
// I know that 'a' has been allocated this chunk of memory X times
// and free(a) has been called less than X times.
I have no idea of that condition, so don't know whether 'a' has been freed or not! So now how would I be sure if 'b' i.e. 'a' has been freed or not.
If you want to make sure that subsequent calls of free on a pointer to dynamically allocated memory will not do any harm, you should assign NULL to that pointer. Because (emphasis added):
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.
If you want to make sure that pointer b will always refer to the same object the other pointer a points at, you could turn b into a pointer to a instead (and dereference it each time you need to use it):
#include <stdio.h>
#include <stdlib.h>
int main() {
/* dynamically allocate some memory */
int *a = malloc(40);
/* b is a pointer to a pointer to an int */
int **b;
/* make b point to a */
b = &a;
if ( 1 ) {
/* free memory and assign NULL to the pointer */
free(a);
a = NULL;
}
/* nothing bad will happen when we dereference b now */
printf("%p\n", *b);
/* nothing bad will happen when we free the memory region
where the pointer b points to points to */
free(*b);
}
Another thing on memory leaks. There will be no memory leaked when you double-free the memory. In that case you will stumble into undefined behavior, in which case anything could happen. Simply because you shall not access memory regions that are not your own (anymore) (c.f., this great post).
Instead, you will leak memory when you loose the reference to a block of dynamically allocated memory. For example:
/* allocate some memory */
int *a = malloc(40);
/* reassign a without free-ing the memory before : you now have leaked memory */
a = malloc(40);
The best option is not having two pointers, pointing to the same place, which are freed independently.
But if that's really what you need, then you need a reference count.
The following code implements a very simple reference count mechanism.
When you assign a second pointer to your data, you should use clone_x to increment the reference count.
Each time you free, use free_x, and it will free just once.
Note that this code isn't multithread-safe. If your code is multi-threaded, you need atomic operations, and you need to be very careful with how you use them.
struct x {
int refcount;
int payload;
};
struct x *create_x(int payload) {
struct x *newx = malloc(sizeof(*newx));
if (!newx) return NULL;
newx->payload = payload;
newx->refcount = 1;
return newx;
}
void clone_x(struct x *myx) {
myx->refcount++;
}
void free_x(struct x *oldx) {
oldx->refcount--;
if (oldx->refcount == 0) {
free(oldx);
}
}
You can't. When free(a) is called it is no longer safe to access that memory.
Even if you malloc() new memory and assign the result to a, that memory could be anywhere.
What you're trying to do will not work.
every allocated memory block should have an 'owner', a or b, if a is the owner, pointer b should not release that block, vice versa.

Resources