In the following code segment, after free(x), why does y become 0?
As per my understanding, the memory in the heap that was being pointed to by x, and is still being pointed to by y, hasn't been allocated to someone else, so how can it change to 0?
And moreover, I don't think it is free(x) that changed it to 0.
Any comments?
#include <stdio.h>
int main(int argc, char *argv[])
{
int *y = NULL;
int *x = NULL;
x = malloc(4);
*x = 5;
y = x;
printf("[%d]\n", *y); //prints 5
free(x);
printf("[%d]\n", *y); //why doesn't print 5?, prints 0 instead
return 0;
}
This is undefined behavior, explanations are just speculation.
I can speculate that maybe you are running a debug version of the C library, and that the debug version of free() does zero the pointed area.
What is done in free depends on the implementation. It is not prohibited to zero out the memory after it's freed.
And what you're doing is undefined behavior.
Doesn't y points to the same address as x, after line
y = x;
If you free x, you will also free the memory pointed by y.
If you are wondering why it prints '0', that undefined behavior, but I've seen it as a practice before, that some programmers, sets the freed area to '0'.
Download this video called "Binky the pointer fun video" (it's not a joke, actually is very educative), and you'll get pointers better.
The call to free() will put the memory block that had been allocated by malloc() back onto data structures that the C runtime maintains for the heap (in this case something that might be called the 'free-list).
Manipulating the heap data structures might incidentally change what was being pointed to by y (since the program doesn't own the memory anymore, it has no reason to believe the memory shouldn't change).
In a non-debug build of the program, the runtime typically won't do anything specifically to invalidate freed memory, but as I mentioned, it may still make changes as a result of its own bookkeeping (though since the memory doesn't belong to the caller anymore, the runtime is allowed to do whatever it likes).
In a debug build, the runtime will probably explicitly overwrite the memory to a value that is likely to be invalid if the program does use it in the hopes that it will cause a problem that identifies the problem more readily. Usually the value used to overwrite the freed memory block isn't zero, since zero will often not expose a bug (i.e. NULL pointer checks will cause the code to 'handle' the invalid memory access). For example, MSVC's debug heap manager will overwrite freed memory with the value 0xDD (see When and why will an OS initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete? for more details).
Related
The code is as follow :
#include <stdlib.h>
int num = 3; // Static external variable
int *ptr = #
int main(void)
{
int num2 = 4; // Automatic variable
int *ptr2 = &num2;
free(ptr); //Free static variable
free(ptr2); //Free automatic variable
return 0;
}
I try to compile the above code and it works, I'm curious does the free() function able to free both the static variable and also automatic variable? Or basically it does nothing?
Calling free() on a pointer not returned by memory allocating functions(malloc,calloc etc) causes Undefined Behavior.
Your code has an Undefined Behavior, So the compiler does not need to give you any diagnostic of it and it can show any behavior, it might work, or crash, or literally do anything.
Just avoid writing code which causes an Undefined Behavior is the only solution.
You shouldn't do that. free is only used for memory dynamically allocated from heap by malloc family of functions.
Memory for num is statically allocated in data segment and can't be released. Memory for num2 is allocated in the main's call stack frame and will be released as soon as main returns.
What actually happens depend on implementation of free. There are usually specific data structures maintained in heap to help malloc/free track the allocated and free memory areas. free expects these data structures to be somewhere around the place its argument points to. An when you pass it a pointer which doesn't point to a malloc-allocated heap area, it'll consider garbage data as some useful information and do some strange things. And you're lucky if the result is just an immediate program crash.
I was reading about how stack and heap work when i got to know that when we make a block in c, the variables inside it have local scope but once the block is exit the stack pointer is not readjusted.
So I wrote a simple program to test this:-
#include <stdio.h>
int main(){
int integer;
integer = 10;
{
int integer2;
integer2 = 20;
printf("the address of integer2 is %x\n", &integer2);
}
int* integer2;
printf("enter the memory address of integer2\n");
scanf("%x", &integer2);
int integer3;
integer3 = 40;
printf("%d %d", integer, *integer2);
return 0;
}
And when i run the program and put the memory address of a variable inside the block into a pointer and then dereference it, it gets the exact value, isn't this the same as a memory leak? because there is no way to access the variable from it's name and most probably that variable wont be used again.
This does not indicate a memory leak.
A memory leak is allocated memory that is no longer reachable.
You have not demonstrated that the memory is still allocated. You could get the same result from accessing memory that isn't allocated.
You have not demonstrated that the memory is no longer reachable. You could get the same result from accessing memory that is still reachable.
In reality, the memory is probably still allocated, but it's also still reachable. Once the function exits, the memory will be freed automatically. No leak. You can verify this by calling the function a million times. The programs memory usage will not increase.
Nope. Here's why:
Either it is legal and well-defined to access that address or it isn't.
If it's legal and well-defined to access that address, then you can't have demonstrated a leak or error by accessing it unless you can get a result you can prove is wrong. You haven't done that.
If it's not legal and well-defined to access that address, then accessing that address is undefined behavior. Even if you did demonstrate a leak, all you demonstrated is that undefined behavior can cause a leak, which shouldn't surprise anyone.
”The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it” (C 2018 6.2.4 2).
The lifetime of integer2 starts when program control enters the innermost block containing it (the opening { just before its definition) and ends when execution of that block ends. At the end of the lifetime, what ceases to exist is the reservation of memory.
The memory does not go away1. Just the guarantee that you can use it goes away. You can still try; the C standard does not prevent you, and compilers mostly do not stop you. But, once that memory is not reserved for integer2, some other code in the program might be using for something else, and you might break the program when you try to use it for integer2.
In other words, as long as the memory is reserved for use for integer2, the compiler has arranged for your program to work correctly in that regard. Storing values in integer2 and loading them back will work. Once the memory is no longer reserved, the compiler has not arranged for your program to work correctly if you continue to use integer2.
It is not a memory leak because the program is still tracking what memory is reserved for use and what memory is not. It knows where the stack pointer is and where it needs to be when the function returns, and it manages that correctly. If you write:
{
int integer2;
integer2 = 20;
printf("the address of integer2 is %p\n", (void *) &integer2);
}
{
int integer4;
integer4 = 40;
printf("the address of integer4 is %p\n", (void *) &integer4);
}
then the compiler might use the same memory for integer2 and integer4, because, once the memory is no longer reserved for integer2, the compiler may reuse it for integer4. If you get the same address when you run this, it shows the lifetime of integer2 did indeed end, and the compiler is tracking memory and reusing it for other purposes, so it is not leaking.
(Incidentally, do not print address with %x. Cast the address to void * and print it with %p.)
Footnote
1 Usually. It is possible for the operating system to take memory away, but that generally does not happen in these situations.
What happens to the data that is present in a memory location that has just been freed by a free() ? Is that data also deleted and the memory will now have a garbage value ? Or that data still persists there untill a new data is stored in that memory location (in future) ?
I mean, for code below:
int *ptr;
ptr = malloc(sizeof(int));
*ptr = 1;
// Suppose ptr = 2000
//Free now
free(ptr);
// My question is what is the value stored in memory address 2000 now ?
// Is it still '1' or some garbage value ?
The result is unpredictable. There are several options that can happen. The point is that you cannot rely on any behavior of the memory released by free()
Some examples:
the memory can be untouched (remain the same as it is with the same data).
It can be given to another memory allocation, in which case it can be written over at any point.
It can be zeroed.
The page containing the memory can be returned to the OS, removing it from the memory map of your process, making your program crash if you try to access it.
Whether or not the value is overwritten is undefined. Once free is called it is allowed to leave the memory as-is or it can overwrite it, but if you are interested in security you should overwrite it yourself before deallocating it. Speaking of deallocation, free doesn't have to give the memory back to the operating system, and in fact in many cases it won't, instead it will keep the memory allocated to your program so that the next time you call malloc it can simply give you back the same memory and avoid having to make more system calls, since the time it takes for memory allocation from the operating system is generally considered a less efficient use of resources than the program keeping a bit more memory allocated than it needs.
I know that using the C free() function the memory used is released, but neither the pointer, nor the value contained in the memory is modified! free() only tells that the memory may be used for other purposes. (It may be some libraries implementations clean the freed memory or the pointer value, but this should not be the standard!)
I tried the code below with gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
int main(void)
{
int *i,j;
i=malloc(100*sizeof(int));
for(j=0;j<100;j++)
i[j]=j+1;
printf("%p %d\n",i,i[0]);
free(i);
printf("%p %d\n",i,i[0]);
return 0;
}
The output results (as I expected) is:
0x1de2010 1
0x1de2010 1
Malloc() is a library function. The answer depends upon how the library is implemented.
Most (if not all) mallocs prefix a header to the memory block returned. This is usually modified.
Some mallocs append a trailer to the memory block and write something to it. This is used to detect buffer overruns.
Some frees() will overwrite the write the returned memory with some bit pattern to detect subsequent writes.
There are a lot of mallocs out there that you can download and link with your application so you can get nearly any behavior you want by linking the malloc you want with your application.
It depends on the compiler. If you are using gcc then after free value of that memory is become 0.
Here is a sample code:
#include<stdio.h>
#include<stdlib.h>
int main ( void )
{
int *ptr = NULL;
ptr = malloc (sizeof(int));
*ptr = 5;
printf ( "\n value of *ptr = %d", *ptr );
free ( ptr );
printf ( "\n value of *ptr = %d", *ptr );
return ( 0 );
}
o/p:
./a.out
value of *ptr = 5
value of *ptr = 0
./a.out
value of *ptr = 5
value of *ptr = 0
./a.out
value of *ptr = 5
value of *ptr = 0
Dereferencing a freed pointer leads to undefined behavior, which means anything is allowed to happen.
Most likely, you'll get some garbage value, but you might also trigger a segmentation fault, which will crash your program. Even so, neither of those behaviors are guaranteed, and you shouldn't rely on them.
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
I've a question about the memory management in C (and GCC 4.3.3 under Debian GNU/Linux).
According to the C Programming Language Book by K&R, (chap. 7.8.5), when I free a pointer and then dereference it, is an error. But I've some doubts since I've noted that sometimes, as in the source I've pasted below, the compiler (?) seems to work according a well-defined principle.
I've a trivial program like this, that shows how to return an array dynamically allocated:
#include <stdio.h>
#include <stdlib.h>
int * ret_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i*2;
}
printf("Address pointer in ret_array: %p\n", (void *) arr);
return arr;
}
int * ret_oth_array(int n)
{
int * arr = (int *) malloc(10 * sizeof(int));
int i;
for (i = 0; i < n; i++)
{
arr[i] = i+n;
}
printf("Address pointer in ret_oth_array: %p\n", (void *) arr);
return arr;
}
int main(void)
{
int *p = NULL;
int *x = NULL;
p = ret_array(5);
x = ret_oth_array(6);
printf("Address contained in p: %p\nValue of *p: %d\n", (void *) p, *p);
free(x);
free(p);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
If I try to compile it with some arguments: -ansi -Wall -pedantic-errors, it doesn't raises errors or warning. Not only; it also runs fine.
Address pointer in ret_array: 0x8269008
Address pointer in ret_oth_array: 0x8269038
Address contained in p: 0x8269008
Value of *p: 0
Memory freed.
*p+4 = 8
*x = 0
*(p+4) is 8 and *x is 0.
Why does this happen?
If *(p+4) is 8, shouldn't *x be 6, since the first element of the x-array is 6?
Another strange thing happens if I try to change the order of the calls to free.
E.g.:
int main(int argc, char * argv[])
{
/* ... code ... */
free(p);
free(x);
printf("Memory freed.\n");
printf("*(p+4) = %d\n", *(p+4));
printf("*x = %d\n", *x);
return 0;
}
In fact in this case the output (on my machine) will be:
*p+4 = 8
*x = 142106624
Why does the x pointer is really "freed", while the p pointer is freed (I hope) "differently"?
Ok, I know that after freeing memory I should make the pointers to point to NULL, but I was just curious :P
It is undefined behaviour, so it is an error to deference freed pointer as strange things may (and will) happen.
free() doesn't change the value of the pointer so it keeps pointing to the heap in the process address space - that's why you don't get segfault, however it is not specified and in theory on some platforms you can get segfault when you try to dereference pointer immediately after freeing.
To prevent this it is a good habit to assign pointer to NULL after freeing so it will fail in predictable way - segfault.
Please note that on some OSes (HP-UX, may be some others as well) it is allowed to dereference NULL pointer, just to prevent segfault (and thus hiding problems). I find it rather stupid as it makes things much more difficult to diagnose, although I don't know the full story behind this.
free() (and malloc()) are not from gcc. They come from the C library, which on Debian is usually glibc. So, what you are seeing is glibc's behavior, not gcc's (and would change with a different C library, or a different version of the C library).
I particular, after you use free() you are releasing the memory block malloc() gave you. It's not yours anymore. Since it is not supposed to be used anymore, the memory manager within glibc is free to do whatever it wants with the memory block, including using parts of it as its own memory structures (which is probably why you are seeing its contents change; they have been overwritten with bookkeeping information, probaly pointers to other blocks or counters of some sort).
There are other things that can happen; in particular, if the size of your allocation was large enough, glibc can ask the kernel for a separate memory block for it (with mmap() or similar calls), and release it back to the kernel during the free(). In that case, your program would crash. This can in theory also happen in some circunstances even with small allocations (glibc can grow/shrink the heap).
This is probably not the answer you are looking for, but I'll give it a try anyway:
Since you're playing with undefined behaviour that you should never depend on in any way, shape or form, what good does it do to know how exactly one given implementation handles that?
Since gcc is free to change that handling at any given time, between versions, architectures or depending on the position and brightness of the moon, there's no use whatsoever in knowing how it handles it right now. At least not to the developer that uses gcc.
*(p+4) is 8 and *x is 0. Why does this happen? If *(p+4) is 8, shouldn't *x be 6, since the first element of the x-array is 6?
One possible explanation for this would be that printf("...%i..."...) might internally use malloc to allocate a temporary buffer for it's string interpolation. That would overwrite the contents of both arrays after the first output.
Generally, I would consider it an error if a program relies on the value of a pointer after it has been freed. I would even say that it's a very bad code smell if it keeps the value of a pointer after it has been freed (instead of letting it go out of scope or overwriting it with NULL). Even if it works under very special circumstances (single-threaded code with a specific heap manager).
Once you free the dynamic-memory variable, it is not yours. The memory manager is free to do what ever it sees better with that piece of memory you where pointing to. The compiler doesn't do anything as far as I know with the freed blocks of memory, because it is a function and not defined by the language. Even if it is defined by the languages, the compiler just inserts calls to the underlying OS functions.
Just wanna say, It is undefined by the language, So you have to check your OS and watch that piece of memory after freeing it. The behavior maybe random, because sometimes other programs ask for memory, sometimes not!
by the way, It is different on my machine, the value changes for both pointers.
Although the behavior you're seeing seems to be consistent, it is not guaranteed to be so. Unforeseen circumstances may causes this behavior to change (let alone the fact that this is completely implemetnatation dependent).
Specifically, in your example you free() the array and then get the old content when you access the array. If you'll have additional malloc() calls after the free() - chances are that the old contents will be lost.
Even if the memory is freed, it is not necessarily reused for some other purpose. Old pointers to your process memory are still valid pointers (though to unallocated memory) so you do not get segmentation faults either.