1
#include <stdio.h>

void function()
{
    int stackVar = 10;
    printf("Stack variable = %d\n", stackVar);
}

int main(void)
{
    function();
    return 0;
}

What happens to the stack frame of function when it returns?

Anish Ramaswamy
  • 2,326
  • 3
  • 32
  • 63
  • 1) you initialized the *pointer* `*x` to the return from "function()". 2) You never initialized what `*x* *points to*. So `printf ("%d", *x)` is printing uninitialized data. – paulsm4 Apr 18 '13 at 06:38
  • @paulsm4 The OP seems to know what he do. Also, the function returns a pointer to a stack variable, so `int* x` technically initialized. – Alex Apr 18 '13 at 06:41
  • @paulsm4 `x` is an `int *` that gets the value returned by `function()`, which in this case is the address of `stackVar`. The `printf()` statement prints the value at that address, i.e. `*x`. Don't confuse the `*x` in `int *x` with the `*x` in `printf(..., *x)`. – Caleb Apr 18 '13 at 06:42
  • It has to be said, cause i'm pedantic like that: The C standard doesn't mention stack frames. In fact, it conspicuously avoids even using the *word* "stack". Even once. Any usage of a stack is purely an implementation detail. Standardswise, the phrase you want to look up is "automatic storage duration". – cHao Apr 18 '13 at 06:47
  • No matter what the behavior is when a function returns, your test program complicates the issue by using `printf()` to display `*x`. Being a function itself, `printf()` may put values on the stack, thus overwriting the value of `stackVar` that was put there when `function()` was invoked. If the value if left on the stack could be stomped on at any moment by the next function call, it's hard to see why it really matters what happens to old stack values unless you're concerned about security. – Caleb Apr 18 '13 at 06:48
  • @jogojapan, Actually my main question was, what happens to the stack frame of a function on return. Those questions talk about returning only data. – Anish Ramaswamy Apr 18 '13 at 06:48
  • @Lundin, Actually my main question was, what happens to the stack frame of a function on return. Those questions talk about returning only data. – Anish Ramaswamy Apr 18 '13 at 06:49
  • @cHao, Yes. I realized that. Thank you for pointing it out :) – Anish Ramaswamy Apr 18 '13 at 06:50
  • @Caleb, Since that invokes undefined behaviour, I guess there's no point analysing it. But, I'd still like to understand what happens to the stack upon return. Just for the sake of knowledge. – Anish Ramaswamy Apr 18 '13 at 06:51
  • @AnishRam The possible duplicate I linked talks about returning a _pointer to_ local data. Ok, that's not proof that the questions are identical, but I am not sure I understand what the difference is. – jogojapan Apr 18 '13 at 06:51
  • @jogojapan, Doesn't a stack frame contain more than just the local variables? I've read so many articles describing how stacks are treated but I couldn't find any standard behaviour. Hence this example and question. (or maybe I'm over-complicating things) – Anish Ramaswamy Apr 18 '13 at 06:53
  • 1
    @AnishRam There is nothing in your question mentioning stack frames, or a particular system. Not all computers have stack frames, there are computers without strict alignment requirements that just allocate as much stack space as needed. Furthermore, what happens depends completely on the system-specific calling convention. And the local variable may as well be allocated in a CPU register, you can't know that. No matter, this is such a FAQ. Just accept that you can get any random value in the variable (including the right result) if accessed beyond its lifetime. – Lundin Apr 18 '13 at 06:54
  • 1
    I just remembered [this classic post](http://stackoverflow.com/questions/6441218/can-a-local-variables-memory-be-accessed-outside-its-scope) on the topic. – Lundin Apr 18 '13 at 06:56
  • 1
    @AnishRam Ok. I guess you would like to understand how call stacks work in general. That would indeed be a different question. But then there is the problem that you give specific C code, which unfortunately has undefined behaviour, which kind of pulls the possible answers into a different direction. Anyway.. if your question gets closed and you think it shouldn't, you can edit it to make it more specific and send me another comment; I am ready to vote to re-open if seems justified. Sorry for the inconvenience. – jogojapan Apr 18 '13 at 06:59
  • *if the treatment of the stack frame upon return is not unspecified/undefined, what exactly happens to the stack frame upon return* **If the treatment is unspecified or undefined, then what exactly happens obviously depend on the particulars of the system in question.** Maybe the stack frame is erased. Maybe it's left there to be overwritten by the next function call. Maybe it never existed at all. There are probably different answers even on the same system, depending on number of function parameters and local variables, compiler flags, etc. – Caleb Apr 18 '13 at 07:01
  • @jogojapan, Okay I think I've removed all my misleading text. Thank you so much for being so helpful :) – Anish Ramaswamy Apr 18 '13 at 07:13
  • @Caleb, So there's no point in trying to understand this? – Anish Ramaswamy Apr 18 '13 at 07:14
  • @AnishRam There's no point in trying to understand it generally because there's not a general answer -- different compilers will handle it differently. And understanding it on a specific system won't help you (you should *never* rely on this sort of behavior) unless you're actually working on the compiler. (And in that case you can look at the compiler source code and figure out what it does.) – Caleb Apr 18 '13 at 15:00

4 Answers4

4

This is undefined behaviour (as opposed to implementation-defined or unspecified). This means that the program is free to misbehave, or not, in any way is pleases.

This is spelled out in 6.2.4 Storage durations of objects:

1 An object has a storage duration that determines its lifetime. There are three storage durations: static, automatic, and allocated. Allocated storage is described in 7.20.3.

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, and retains its last-stored value throughout its lifetime. 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.

3 An object whose identifier is declared with external or internal linkage, or with the storage-class specifier static has static storage duration. Its lifetime is the entire execution of the program and its stored value is initialized only once, prior to program startup.

4 An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration.

5 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way. (Entering an enclosed block or calling a function suspends, but does not end, execution of the current block.) If the block is entered recursively, a new instance of the object is created each time. The initial value of the object is indeterminate. If an initialization is specified for the object, it is performed each time the declaration is reached in the execution of the block; otherwise, the value becomes indeterminate each time the declaration is reached.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

Firstly, you've edited the question dramatically, so other answers are (somewhat unfairly) no longer relevant. Still, to answer the current question:

What happens to the stack frame of function when it returns?

It seems to me you lack a general feel for how the stack operates. So - going a bit crazy here - but will try an analogy that might make it "click". You can imagine the stack frame as being like waves on the beach. The more deeply nested function calls get, and the more data those functions have in parameters and local variables, the more memory is in use. That's like waves reaching further up the beach. As scopes exit the memory is effectively released - the use to which that memory was put is forgotten. So too do waves recede. Still, throughout the lifetime of the program as different sequences of functions enter and exit, the same memory (level of the beach) is reused (under water) and forgotten (not under water). The bits furthest up the beach tend to be covered least often and for short durations, while some stays underwater until the weakest point of low tide... similarly things like recursive functions that aren't tail-recursion optimised can use a lot of memory briefly, but the stack variables created directly in main() stay there until program termination.

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252
  • Yes I realize. I apologised to the answerers. So does this mean that stack frames are allocated as functions are entered? So all those `push` instructions do the allocations? So this memory usage is similar to that of `malloc` and `free` since `free` just _marks_ the memory as free (so it can later be overwritten)? (<- that's a helluva lotta questions) – Anish Ramaswamy Apr 18 '13 at 07:52
  • @AnishRam: pretty much yes to all of that. The implementation has a thing called the "stack pointer", which points to the "current stack position". `push` instructions store a value and move the stack pointer. When a function returns, it puts the stack pointer back to whatever value it had on function entry (perhaps it also pops its own parameters, as a feature of the calling convention). That's it. Not every implementation is the same (for example gcc has `-fsplit-stack`, and most modern OSes page in stack when it is first used rather than up front), but that's how call stacks *usually* work. – Steve Jessop Apr 18 '13 at 08:30
  • @AmishRam: to add to what Steve's said, you typically either push some specific value onto the stack - which moves the stack pointer by an amount corresponding to that data size (later popping it off and reversing the stack pointer movement), or the compiler works out the total size of a number of variables (e.g. all those required as a new function call begins) and adds that much to the stack pointer in one instruction then references specific variables on the stack using a number-of-bytes offset. – Tony Delroy Apr 18 '13 at 13:38
  • @AmishRam: "So this memory usage is similar to that of malloc and free since free just marks the memory as free (so it can later be overwritten)?" In the limited sense that the freed memory hangs around until it's allocated, that's exactly right. Of course, malloc and free can't just increase and decrease the total heap usage though, as the lifetime for which the data is needed isn't ordered the way it is for variables on the stack. – Tony Delroy Apr 18 '13 at 13:47
0

You are invoking undefined behavior.
When you return from the function, the stack frame is destroyed (goes out of scope) and it might be you receive the value you left in the function, but this would be a coincidence.

See Wikipedia for some examples and here for an article.

Lundin
  • 195,001
  • 40
  • 254
  • 396
bash.d
  • 13,029
  • 3
  • 29
  • 42
0

undefined behavior. you are returning local variable address from the function, because the stack-frame is destroyed (out of scope) . Now if memory (address )is not overwritten then you will get same value else you will get garbage .

anshul garg
  • 473
  • 3
  • 7
  • Regarding this: _...if memory is not overwritten then you will get same value:_ You make it sound as if undefined behaviour was defined after all. – jogojapan Apr 18 '13 at 06:46
  • the stack frame is not "destroyed" – UmNyobe Apr 18 '13 at 06:48
  • @jogojapan , Behavior is undefined because you can't guess whether that memory is available(i.e. not allocated) that's why result would be unpredictable. – anshul garg Apr 18 '13 at 06:50
  • @UmNyobe As soon as function returns stack frame corresponding to it gets destroyed..if it is not the case then how memory taken by frame will be freed – anshul garg Apr 18 '13 at 06:51
  • @anshulgarg But that is not the point. Example: If the compiler realizes that certain parts of your code cause undefined behaviour (and that would be readily possible in the code the OP gave), it can do whatever it wants. It does not actually have to generate machine code that looks at the original address of the local variable. It can therefore give you garbage even if the original memory wasn't overridden, and much worse things can happen, too. – jogojapan Apr 18 '13 at 06:53
  • @jogojapan yes thats right.. thanks for correcting me. – anshul garg Apr 18 '13 at 06:55
  • In several implementations the stack frame allocation\release is just a movement of a stack pointer. So the term `destroyed` is, how can I say that, too strong. – UmNyobe Apr 18 '13 at 07:58