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.
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.
In most managed languages (that is, the ones with a GC), local variables that go out of scope are inaccessible and have a higher GC-priority (hence, they'll be freed first).
Now, C is not a managed language, what happens to variables that go out of scope here?
I created a small test-case in C:
#include <stdio.h>
int main(void){
int *ptr;
{
// New scope
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
//printf("tmp = %d", tmp); // Compile-time error (as expected)
printf("ptr = %d\n", *ptr);
return 0;
}
I'm using GCC 4.7.3 to compile and the program above prints 17, why? And when/under what circumstances will the local variables be freed?
The actual behavior of your code sample is determined by two primary factors: 1) the behavior is undefined by the language, 2) an optimizing compiler will generate machine code that does not physically match your C code.
For example, despite the fact that the behavior is undefined, GCC can (and will) easily optimize your code to a mere
printf("ptr = %d\n", 17);
which means that the output you see has very little to do with what happens to any variables in your code.
If you want the behavior of your code to better reflect what happens physically, you should declare your pointers volatile. The behavior will still be undefined, but at least it will restrict some optimizations.
Now, as to what happens to local variables when they go out of scope. Nothing physical happens. A typical implementation will allocate enough space in the program stack to store all variables at the deepest level of block nesting in the current function. This space is typically allocated in the stack in one shot at the function startup and released back at the function exit.
That means that the memory formerly occupied by tmp continues to remain reserved in the stack until the function exits. That also means that the same stack space can (and will) be reused by different variables having approximately the same level of "locality depth" in sibling blocks. The space will hold the value of the last variable until some other variable declared in some sibling block variable overrides it. In your example nobody overrides the space formerly occupied by tmp, so you will typically see the value 17 survive intact in that memory.
However, if you do this
int main(void) {
volatile int *ptr;
volatile int *ptrd;
{ // Block
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
{ // Sibling block
int d = 5;
ptrd = &d;
}
printf("ptr = %d %d\n", *ptr, *ptrd);
printf("%p %p\n", ptr, ptrd);
}
you will see that the space formerly occupied by tmp has been reused for d and its former value has been overriden. The second printf will typically output the same pointer value for both pointers.
The lifetime of an automatic object ends at the end of the block where it is declared.
Accessing an object outside of its lifetime is undefined behavior in C.
(C99, 6.2.4p2) "If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime."
Local variables are allocated on the stack. They are not "freed" in the sense you think about GC languages, or memory allocated on the heap. They simply go out of scope, and for builtin types the code won't do anything - and for objects, the destructor is called.
Accessing them beyond their scope is Undefined Behaviour. You were just lucky, as no other code has overwritten that memory area...yet.
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.
In most managed languages (that is, the ones with a GC), local variables that go out of scope are inaccessible and have a higher GC-priority (hence, they'll be freed first).
Now, C is not a managed language, what happens to variables that go out of scope here?
I created a small test-case in C:
#include <stdio.h>
int main(void){
int *ptr;
{
// New scope
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
//printf("tmp = %d", tmp); // Compile-time error (as expected)
printf("ptr = %d\n", *ptr);
return 0;
}
I'm using GCC 4.7.3 to compile and the program above prints 17, why? And when/under what circumstances will the local variables be freed?
The actual behavior of your code sample is determined by two primary factors: 1) the behavior is undefined by the language, 2) an optimizing compiler will generate machine code that does not physically match your C code.
For example, despite the fact that the behavior is undefined, GCC can (and will) easily optimize your code to a mere
printf("ptr = %d\n", 17);
which means that the output you see has very little to do with what happens to any variables in your code.
If you want the behavior of your code to better reflect what happens physically, you should declare your pointers volatile. The behavior will still be undefined, but at least it will restrict some optimizations.
Now, as to what happens to local variables when they go out of scope. Nothing physical happens. A typical implementation will allocate enough space in the program stack to store all variables at the deepest level of block nesting in the current function. This space is typically allocated in the stack in one shot at the function startup and released back at the function exit.
That means that the memory formerly occupied by tmp continues to remain reserved in the stack until the function exits. That also means that the same stack space can (and will) be reused by different variables having approximately the same level of "locality depth" in sibling blocks. The space will hold the value of the last variable until some other variable declared in some sibling block variable overrides it. In your example nobody overrides the space formerly occupied by tmp, so you will typically see the value 17 survive intact in that memory.
However, if you do this
int main(void) {
volatile int *ptr;
volatile int *ptrd;
{ // Block
int tmp = 17;
ptr = &tmp; // Just to see if the memory is cleared
}
{ // Sibling block
int d = 5;
ptrd = &d;
}
printf("ptr = %d %d\n", *ptr, *ptrd);
printf("%p %p\n", ptr, ptrd);
}
you will see that the space formerly occupied by tmp has been reused for d and its former value has been overriden. The second printf will typically output the same pointer value for both pointers.
The lifetime of an automatic object ends at the end of the block where it is declared.
Accessing an object outside of its lifetime is undefined behavior in C.
(C99, 6.2.4p2) "If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to reaches the end of its lifetime."
Local variables are allocated on the stack. They are not "freed" in the sense you think about GC languages, or memory allocated on the heap. They simply go out of scope, and for builtin types the code won't do anything - and for objects, the destructor is called.
Accessing them beyond their scope is Undefined Behaviour. You were just lucky, as no other code has overwritten that memory area...yet.
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).