Pointer allocation and Memory Location [duplicate] - c

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 12 months ago.
In an Microprocessor it is said that the local variables are stored in stack. In my case if func1() is called by main function then the local variable (int a = 12;)will be created in stack. Once the Called Function is executed the and return back to main function the stack memory will be deleted. So the pointer address still holds (*b) the value 12. At stack if this 'a = 12' is deleted then 'b' should be a dangling pointer no?? Can anyone explain this ? If you have detailed explanation on what happens in memory when this code is being executed it would be helpful.
#include <stdio.h>
int* func1(void);
int main()
{
int* b = func1();
printf("%d\n",*b);
}
int* func1(void)
{
int a = 12;
int* b = &a;
return b;
}

The pointer is dangling. The memory may still hold the previous value, but dereferencing the pointer invokes undefined behaviour.
GCC will give you a warning about this, if you pass -Wall option.
From the C standard (6.2.4):
The lifetime of an object is the portion of program execution during
which storage is guaranteed to be reserved for it. An object exists,
has a constant address,25) and retains its last-stored value
throughout its lifetime.26) 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.

There are multiple layers here.
First, is the C programming language. It is a language. You say stuff in it and it has meaning. There are sentences that have meaning, but you can also construct grammatically valid sentences that are gibberish.
The code you posted, grammatically valid, is gibberish. The object a inside func1 stops existing when the function returns. *b tries to access an object that does not exists anymore. It is not defined what should happen when you access an object after its lifetime ended. You can read about undefined behavior.
Memory exists. It's not like it is disintegrated when a function returns. It's not like RAM chips are falling out of your PC. They are still there.
So your compiler will produce some machine instructions. These machine instructions will execute. Depending solely on your compiler decisions (the code is undefined behavior, compiler can do what it wants) the actual code can behavior in any way the compiler decides to. But, most probably, *b will generate machine instructions that will read the memory region where object a resided. That memory region may still hold the value 12 or it may have been overwritten somewhere between func1 returning and calling printf, resulting in reading some other value.
At stack if this 'a = 12' is deleted then 'b' should be a dangling pointer no?
Yes.
what happens in memory when this code
This depends on the actual machine instructions generated by the compiler. Compile your code and inspect the assembly.

Strictly speaking, the behaviour is undefined, but repeat the printf or otherwise inspect (in your debugger for example) *b after the printf. It is likely that it will no longer be 12.
It is not accurate to say that the stack memory is "deleted". Rather the stack pointer is restored to the address it had before the call was invoked. The memory is otherwise untouched but becomes available for use by subsequent calls (or for passing arguments to such calls), so after calling printf it is likely to have been reused and modified.
So yes, the pointer is "dangling" since it points to memory that is no longer "valid" in the sense that it does not belong to the context in which the pointer exists.

Related

Function parameters behaving strangely in C

Below is the sample code written in C:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
int* second;
void myTest1(int a, bool check){
if(check){
second = &a;
}
printf("%d", *(second));
printf(" ");
}
int main(int argc, char const *argv[])
{
int a =1;
int b = 2;
int c=3;
myTest1(a,true);
myTest1(b,false);
myTest1(c,false);
}
I expect the output be like
1 1 1
But the actual output is
1 2 3
I am a bit confused about it, void myTest1(int a, bool check) here I believed a should have function scope. But it seems that the memory location of a is reused in every function call.
I am building by using command gcc <filename>.c
Below are some system details:
OS: Ubuntu
GCC compiler version: gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
You are setting second to the address of a variable that goes out of scope at the end of the function invocation. Once the variable is out of scope, the memory it occupied is no longer yours, and it can be reused. That memory address happens to be reused in each subsequent invocation, with the new argument's value copied into it.
Don't store the address of a local variable and access that address after the variable has gone out of scope. This produces undefined behaviour. You cannot make any assumptions about what may be on the other end of that pointer.
Regarding the following:
here I believed a should have function scope
It does...
But it seems that the memory location of "a" is reused in every function call.
Well, reuse is a necessary and natural result of a having "function scope". Unless you are assuming some kind of garbage-collection behavior, where keeping a pointer to this memory prevents it from being reused, a's memory location should be reused once a is inaccessible, otherwise this is the very definition of a memory leak. If the memory for function arguments weren't reused, every function invocation would leak memory by design.
In C and C++ it's your job not to store the address of stack-allocated variables that have gone out of scope (or at least, not to try to use that address after the variable has gone out of scope). The act of storing an address in a pointer does not innately protect that memory from reuse. It's up to you to either allocate that memory on the heap and manage its lifetime yourself, or to allow the stack to manage your memory and not hold onto pointers that outlive the lifetime the variables they point to.
You're causing undefined behavior. When a function returns, all its automatic variables are destroyed, and any pointers to them become invalid.
On the second and third calls to myTest1(), second points to a variable from the first call. Since this variable no longer exists, dereferencing the pointer results in undefined behavior.
You're getting the result you see because in practice each successive call to the function happens to use the same location for the stack frame. So the address of a in each call is the same, so the old pointer will point to the value that was passed in the new call.

Address of the automatic storage class variable assigned to a local variable of another function [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
How to access a local variable from a different function using pointers?
(10 answers)
Closed 4 years ago.
#include <stdio.h>
int* function1(void);
int main()
{
int x = 10;
int *p = function1();
printf("%d\n", *p);
printf("%d\n", p);
}
int* function1(void)
{
int z;
z = 20;
z++;
return &z;
}
Variable 'z' is local to the 'function1', and is not alive after the
'function1' is terminated.
Now to access the value at the memory space of the variable 'z', its
address is returned by the function.
So, even after the termination, will the memory space of the variable
'z' will still be reserved, as the pointer accesses the variable?, in such case what will be the properties of the memory space?
Or What if some-other variable is allocated with the same memory space
of variable 'z'?
Note: GCC compiler of code blocks has compiled the program successfully, without any error and warning.
In general what you do is undefined.
However, on Intel architectures z is on the stack and after return, if you don't call any other function the value will probably still be available because the memory has not yet been reused. As soon as you call another function, the memory will probably be overwritten and so will contain garbage for you.
In general: Don't do this!
The variable z does no longer exist after the function function1 finishes it's execution. In function main you are trying to reference a memory address which has been deallocated after the function's call. This will cause undefined behavior.
When the function call happens, all your local variables will be in stack. During function call, the stack variables can be modified. When the function call returns, the stack pointer is decremented’
Hence, you will be accessing something which is not guaranteed in any way. In programming languages, this is addressed as a case of undefined behaviour, since you are overriding the rules of programming language.
In this case of function, given that you stack frame is still active and not modified by any other code, you might get the same value that you wrote to that address.
But is not guaranteed in anyway and dont assume anything not guaranteed.

C - What Happens To Memory After free()? [duplicate]

This question already has answers here:
What happens to memory after free()?
(4 answers)
Closed 9 years ago.
I have this struct type that I malloc for, and after I free it the pointer still points to the data I assigned. Is that just because the pointer is pointing to memory that is free but hasn't been reallocated yet?
#include <stdio.h>
struct S {
int value;
}
int main () {
S *s = malloc(sizeof(struct S));
s->value = 8910;
free(s);
printf("s: %i\n", s->value);
}
Freed memory doesn't belong to you anymore. But that doesn't mean it disappears or gets changed in any way. Why would your program bother? It would be a waste of time. It probably just marks the memory as available for use by subsequent malloc()s, and that's it. Or it might not. Using memory that doesn't belong to you might do anything: return wrong values, crash, return right values, or run a flight simulator game. It's not yours; don't mess with it and you'll never have to worry about what it might do.
The C standard defines the behavior of the free function:
The free function causes the space pointed to by ptr to be
deallocated, that is, made available for further allocation.
which means that a later call to malloc (or something else) might re-use the same memory space.
As soon as a pointer is passed to free(), the object it pointed to reaches the end of its lifetime. Any attempt to refer to the pointed-to object has undefined behavior (i.e., you're no longer allowed to dereference the pointer).
More than that, the value of the pointer itself becomes indeterminate, so any attempt to refer to the pointer value has undefined behavior. Reference: N1570 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 (or just past) reaches the end of its lifetime.
It's true that free()'s argument is passed by value (like all C function arguments), and so free can't actually modify the pointer. One way to think of it is that the pointer has the "same" value before and after the call, but that value is valid before the call and indeterminate after the call.
It's likely that an attempt to refer to the pointer value, or even to dereference it, will appear to "work". That's one of the many possible symptoms of undefined behavior (and arguably the worst, since it makes it difficult to detect and diagnose the error).
free() just declares, to the language implementation or operating system, that the memory is no longer required. When it is written over is not defined behavior.

Scope of a variable. Internal working basic

This is a very basic question about the scope of a variable suppose. I have the fiollowing code:
int main()
{
int *p;
p=func();
printf("%d",*p);
return 0;
}
int *func()
{
int i;
i=5;
return &i;
}
My question
The scope of i is finished in func() but, since I am returning the address of i will I be able to access and print5 in main()?
If not, why? does the compiler puts a garbage value in that address space (I don't think this is done).
What actually it means by the scope of a variable is ended ? Also does the memory allocated to i is freed when its scope ends?
Scope of the variable is the region where it can be accessed.
Lifetime of the variable is the time till when the variable is guaranteed to exist.
In your case lifetime of i is within the function not beyond it. It means i is not guaranteed to exist beyond the function. It is not required to and it is Undefined Behavior to access a local variable beyond the function.
The scope of i is finished in func() but, since I am returning the address of i will I be able to access and print 5 in main()?
You might, but it is Undefined Behavior. So don't do it.
If not, why? does the compiler puts a garbage value in that address space (I don't think this is done)
The compiler may put whatever it chooses to in that location, once the function returns the address location is holds an Indeterminate value.
What actually it means by the scope of a variable is ended ? Also does the memory allocated to i is freed when its scope ends?
i is a automatic/local variable and all automatic variables are freed once the scope {,} in which they are declared ends. Hence the name automatic.
It is undefined behaviour to access a variable after it has gone out of scope. This means it is not possible to say what will definitely happen. In the posted code, 5 might be printed, some other value may be printed or some other behaviour may occur (access violation for example).
Behaviour in your example is undefined. Your printf probably will output 5 but that'd be down to luck rather than good design.
In this case, when the scope of the variable is ended, further function calls may reuse the stack address &i changing the value your p variable points to.
No, accessing a variable that has gone out of scope leads to undefined behavior. The storage where thev variable used to be has been reclaimed, so you're likely to overwrite something else which can lead to crashes or just unpredictable behavior.
Your function will probably print 5, but you should never do this. It's undefined behavior since your program no longer owns the location pointed to by the pointer your return (in other words, your program no longer owns i).
Basically each time a function is called, the stack pointer is pushed down to accommodate the new stack frame. When the function call ends, the stack pointer is raised back up. This means that if a different function were to be called, it would have overlapping the same stack space as the previous function call.
To illustrate this a little better, consider this:
int main()
{
int *p;
p=func();
printf("%d\n",*p);
func2();
printf("%d\n",*p);
return 0;
}
int *func()
{
int i;
i=5;
return &i;
}
void func2()
{
int i = 1;
}
There's a pretty good chance that the output would be 5 1. This is because the second call will reuse the same stack space.
(Note that above code snippet is horrible -- you should never do something like that -- it's undefined behavior and highly implementation dependent.)
To answer your questions directly:
The scope of i is finished in func() but, since I am returning the address of i will I be able to access and print5 in main()?
No. You can, but you shouldn't. Such is the beauty of C. Depending on the compiler/OS/etc it might output 5, or it might output random garage.
If not, why? does the compiler puts a garbage value in that address space (I don't think this is done).
The space used for local variables is reused. The first half of the answer hopefully illustrated how this works. (Well, how it typically works.)
What actually it means by the scope of a variable is ended ? Also does the memory allocated to i is freed when its scope ends?
Stack based memory allocation is what's going on behind the scenes.

Ampersand bug and lifetime in c

As we know, local variables have local scope and lifetime. Consider the following code:
int* abc()
{
int m;
return(&m);
}
void main()
{
int* p=abc();
*p=32;
}
This gives me a warning that a function returns the address of a local variable.
I see this as justification:
Local veriable m is deallocated once abc() completes. So we are dereferencing an invalid memory location in the main function.
However, consider the following code:
int* abc()
{
int m;
return(&m);
int p=9;
}
void main()
{
int* p=abc();
*p=32;
}
Here I am getting the same warning. But I guess that m will still retain its lifetime when returning. What is happening? Please explain the error. Is my justification wrong?
First, notice that int p=9; will never be reached, so your two versions are functionally identical. The program will allocate memory for m and return the address of that memory; any code below the return statement is unreacheable.
Second, the local variable m is not actually de-allocated after the function returns. Rather, the program considers the memory free space. That space might be used for another purpose, or it might stay unused and forever hold its old value. Because you have no guarantee about what happens to the memory once the abc() function exits, you should not attempt to access or modify it in any way.
As soon as return keyword is encountered, control passes back to the caller and the called function goes out of scope. Hence, all local variables are popped off the stack. So the last statement in your second example is inconsequential and the warning is justified
Logically, m no longer exists when you return from the function, and any reference to it is invalid once the function exits.
Physically, the picture is a bit more complicated. The memory cells that m occupied are certainly still there, and if you access those cells before anything else has a chance to write to them, they'll contain the value that was written to them in the function, so under the right circumstances it's possible for you to read what was stored in m through p after abc has returned. Do not rely on this behavior being repeatable; it is a coding error.
From the language standard (C99):
6.2.4 Storage durations of objects
...
2 The lifetime of an object is the portion of program execution during which storage is
guaranteed to be reserved for it. An object exists, has a constant address,25) and retains
its last-stored value throughout its lifetime.26) 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.
25) The term ‘‘constant address’’ means that two pointers to the object constructed at possibly different
times will compare equal. The address may be different during two different executions of the same
program.
26) In the case of a volatile object, the last store need not be explicit in the program.
Emphasis mine. Basically, you're doing something that the language definition explicitly calls out as undefined behavior, meaning the compiler is free to handle that situation any way it wants to. It can issue a diagnostic (which your compiler is doing), it can translate the code without issuing a diagnostic, it can halt translation at that point, etc.
The only way you can make m still valid memory (keeping the maximum resemblance with your code) when you exit the function, is to prepend it with the static keyword
int* abc()
{
static int m;
m = 42;
return &m;
}
Anything after a return is a "dead branch" that won't be ever executed.
int m should be locally visible. You should create it as int* m and return it directly.

Resources