What happens when you access the previous stack variable? [duplicate] - c

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 4 years ago.
I was trying to access a variable from the previous stack and it gave me the following error in Linux:
.... terminated by signal SIGSEGV (Address boundary error
However in CS61C lecture from 2014, the output was coming as:
3
Something Random
How did it even work in that machine vs my Linux?
Why did it print 3 the first time but not the second time? If printf didn't use that slot for something else, that behavior should have happened the second time as well no?
Below is the code:
#include<stdio.h>
int *ptr() {
int y;
y = 3;
return &y;
}
main() {
int *stackAddr, content;
stackAddr = ptr();
content = *stackAddr;
printf("%d", content);
content = *stackAddr;
printf("%d", content);
}

The lecture notes are more about a study of the behaviour of a particular compiler rather than anything else: The assertion in your picture that "Pointers in C allow access to deallocated memory" is not true from a language perspective; the behaviour is merely undefined by the C standard.
Your best bet here therefore is to inspect the generated assembly; this is unanswerable at the language level as the language does not define the behaviour.

Your assumption is not exactly true:
If printf didn't use that slot for something else, that behavior should have happened the second time as well no?
No.
For the first call the illegal memory access is done before calling printf as the parameter must be evaluated before you can call the function. For the second call the expression is evaluated again and anything could have happened in the meantime.
That's what happens if you invoke UB.

Related

Peculiarity in functions of "C" Language [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 2 years ago.
Since i am new to C Language i was learning it from tutorials point when i encountered a peculiarity in functions which got my head banging while understanding it.
I have learnt that if variables are defined inside a function then there scope is local to that function and whenever the control transfers from function the variables are no more available and cleaned.
But its not in the case i have created, the program below is still printing the value of variable p which is defined in the test function so when control from test function is transferred why i am still able to get its value? its still printing the value of variable p that is 80 in screen why?
#include <stdio.h>
int *test();
int main()
{
int *ab
ab = test();
printf("%d\n",*ab);
return 0;
}
int *test()
{
int p = 80;
return (&p);
}
Help me understand this peculiarity Please.
What you are experiencing is a symptom of undefined behavior.
A variable's address is no longer valid after its lifetime ends. When you attempt to dereference that address, you may see the value you had before, or you may see something else.
Try duplicating the printf call in main and you'll likely see a different value.
What is most likely happening is that before the first call to printf the area of memory that contained p hadn't yet been overwritten. Then when printf is actually called, the stack frame for that function is using the same memory that the stack frame for test was using and the memory previously used by p is now overwritten. So when you dereferences ab in main after calling printf you'll see whatever value that function placed there.
Accessing an out-of-scope variable is Undefined Behaviour , and hence, by definition, results can vary infinitely and unpredictably, as variables change (compiler flags, OS, etc.)
Your variable does go out of scope but this only means it is no longer 'reserved'. However, unlike newer languages where this may raise compile-time errors, in C this is merely a warning, which may appear if you specifically ask the compiler to give you extra warnings.
So the code will compile.
Here, the variable goes out of scope, but, assumably, no further usage of memory occurs , and so the value at the address of test stays same . If more variables were declared/initialised/used , then likely that address would have been overwritten with another value, and you would have printed something unexpected - to be real, even this result was unexpected, hence your question !
The thing to remember is - variables in C are like chairs in a hall(which is akin to memory). The chair's position, the number of chairs is all static/fixed. What can be changed is who sits at what chair.
So, if you ask a friend to sit at a convenient chair and 5 minutes later tell him he is no longer required , whether he stays there or gets up and someone takes his place is something you cannot predict without looking and reading at an out-of-scope address is similarly undefined , since it cannot be predicted beforehand !
Other analogies may be parking spaces, ship-containers, etc.
The difference is that the address won't be overwritten / 'deleted' until something else comes up which needs to be stored (this is also how Disks manage 'deletion' which is actually nothing but un-reserving hardware locations) .
And when you think about it, it makes a lot of sense from the efficiency standpoint - you no longer have to waste time doing a useless 'overwrite with 0' or whatever and instead only write when you have a real value to store to memory !
( 1 operation instead of 2, half the work.)
Even though the variable shouldn't be "existing" anymore, the computer is a little bit lazy, and it won't delete the value at an address.
That is how you can manipulate the memory, if you try to see memory that doesn't belong to your program, you'll be able to see some weird values, because they stay in the memory even though they aren't used anymore.
Here is an example that may illustrate the UB you're looking at:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
int *test();
void run_random();
int main()
{
srand(time(NULL));
int *ab;
int i=0, N = 5;
for (i=0; i<N; ++i){
ab = test();
run_random();
printf("%d\n",*ab);
}
return 0;
}
int *test()
{
int p = 80;
return (&p);
}
void run_random()
{
int i=0, N=1000;
for (i=0; i<N; ++i){
int rvar = rand();
}
}
In your code, the variable from test() happens to still have the expected value on the stack memory. This is what I see when re-running the function in a loop - *ab is still equal to 80, you can see it too if you comment out the run_random() call.
But when I add the second call, the call to run_random() - I start getting ab equal to N in the run_random() i.e. 1000, as that memory location is now populated with a different variable's value (it was free to use by the OS to begin with, as soon as test() stopped executing).
In your case you may end up seeing something else, of course, perhaps even still the expected value. That is the point of UB, you don't really know what will pop-up.

C pointers and var scopes [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 5 years ago.
I've a question about var scopes and pointer.
That's an example function:
int *double(int a)
{
int p = a*2;
int *ret = &p;
return ret;
}
And that's the question:
After a fuction return to the caller, it should delete from the memory every variable declared in it.
In this function I only return the addres of "p" (that's declared only in the function) but when I use it in the main, for example, the space of memory allocated by the function "double" hasn't been deleted.
Why?
The memory isn't valid anymore; what happens when you access it after double has returned is undefined behavior. That means that anything is possible:
It could be that the value hasn't been overwritten by something else yet (what likely happened in your case).
It could be that something else has written something to that address, so the value is now random garbage.
It could be that your code opens up a wormhole to a parallel dimension, causing an invasion of evil space octopi that dooms us all.
So, basically, I don't recommend it.

How is memory allocation being done in this C program? [duplicate]

This question already has answers here:
I want this to crash, but it doesn't
(4 answers)
Closed 7 years ago.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *a[10];
a[2] = (int*)malloc(sizeof(int));
a[2][3]=4;
printf("%d", a[2][3]);
return 0;
}
I have given only the memory equivalent of a single int to the pointer variable. How is that I am able to access an element at index 3 for that pointer of a single int?
That's because nothing is preventing you accessing arrays out of bound and this invokes undefined behavior. Any expected or unexpected behavior of program can be seen.
You can try but the behaviour of your program will be undefined.
C does not perform that kind of checking at runtime.
You're accessing some randomly set RAM element. This is a common C programming mistake and is one of the reason for many security flaws.
The Heartbleed bug would be a nice example, where people were able to read a good portion of the server RAM, by accessing elements outside of the array structure.

Why no error is thrown in compilation or running [duplicate]

This question already has answers here:
Array index out of bound behavior
(10 answers)
Why out of bound array accessible in C? [duplicate]
(3 answers)
Closed 9 years ago.
int main()
{
int a[2] = {1,2};
a[2] = 3;
printf("\n\n%d %d %d\n\n",a[0],a[1],a[2]);
return 0;
}
I get output as 1 2 3
Why no error is thrown at run time or compile time?
Have you heard about all the security problems caused by buffer overruns? They exist because C doesn't have any automatic array bounds checking. It's the programmer's responsibility to ensure that they don't address outside the array limit, the compiler doesn't check for it.
Just make sure you don't address anything out of the boundary since, C doesn't check array bounds.
int a[2] is allocated as an automatic variable on the stack. In Windows the stack is initially allocated as 1MB for a process. So, what has really happened is that when the code assigned a[2] = 3; an area outside of the stack frame for main() was updated.
More often than not this causes a problem, such as a segmentation fault, but in simple programs stuff like this sometimes still works.
An interesting test would be to call a sub-routine that also defines and sets some automatic variables and after it returns print the value of a[2] to see if it got overwritten by the stack frame for the sub-routine? If you do this, please let me know the results!

local memory address is valid after function return? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Can a local variable's memory be accessed outside its scope?
I was refreshing the knowledge about how memory internally works, and I faced the confusion. Here is sample code
int * func(){
int retval = 3;
return &retval;
}
int main(void){
int *ptr = func();
printf("address return from function %p and value %d\n", ptr, *ptr);
}
My understanding regards how stack memory works on a routine, is when a function was called, it is pushed on the stack. And lifetime of local variables within this routine would no longer valid once the function returns. So returning address of local variable seems like not valid, but when I test this code, it actually returns its address and still valid after the function returns.
am I misunderstanding the concept ? Appreciated any comments, Thanks.
"Testing the code" is not a meaningful way to determine if something is valid or not. Your code produces undefined behavior. One possible manifestation of undefined behavior is that the code might appear to be "working". In other words, you simply got lucky.
To answer the question: no, it is not valid to return a pointer to a local variable and it is not valid to dereference such a pointer. Any attempts to do so lead to undefined behavior.

Resources