Gwenael Larmet
Gwenael Larmet

Reputation: 135

Passing Data through the Stack

I wanted to see if you could pass struct through the stack and I manage to get a local var from a void function in another void function.

Do you guys thinks there is any use to that and is there any chance you can get corrupted data between the two function call ?

Here's the Code in C (I know it's dirty)

#include <stdio.h>

typedef struct pouet
{
    int a,b,c;
    char d;
    char * e;
}Pouet;

void test1()
{
    Pouet p1;
    p1.a = 1;
    p1.b = 2;
    p1.c = 3;
    p1.d = 'a';
    p1.e = "1234567890";
    printf("Declared struct              : %d %d %d %c \'%s\'\n", p1.a, p1.b, p1.c, p1.d, p1.e);
}

void test2()
{
    Pouet p2;
    printf("Element of struct undeclared : %d %d %d %c \'%s\'\n", p2.a, p2.b, p2.c, p2.d, p2.e);
    p2.a++;
}

int main()
{
    test1();
    test2();
    test2();
    return 0;
}

Output is :

Declared struct : 1 2 3 a '1234567890'

Element of struct undeclared : 1 2 3 a '1234567890'

Element of struct undeclared : 2 2 3 a '1234567890'

Upvotes: 0

Views: 114

Answers (5)

user3079266
user3079266

Reputation:

Contrary to the opinion of the majority, I think it can work out in most of the cases (not that you should rely on it, though).

Let's check it out. First you call test1, and it gets a new stack frame: the stack pointer which signifies the top of the stack goes up. On that stack frame, besides other things, memory for your struct (exactly the size of sizeof(struct pouet)) is reserved and then initialized. What happens when test1 returns? Does its stack frame, along with your memory, get destroyed?

Quite the opposite. It stays on the stack. However, the stack pointer drops below it, back into the calling function. You see, this is quite a simple operation, it's just a matter of changing the stack pointer's value. I doubt there is any technology that clears a stack frame when it is disposed. It's just too costy a thing to do!

What happens then? Well, you call test2. All it stores on the stack is just another instance of struct pouet, which means that its stack frame will most probably be exactly the same size as that of test1. This also means that test2 will reserve the memory that previously contained your initialized struct pouet for its own variable Pouet p2, since both variables should most probably have the same positions relative to the beginning of the stack frame. Which in turn means that it will be initialized to the same value.

However, this setup is not something to be relied upon. Even with concerns about non-standartized behaviour aside, it's bound to be broken by something as simple as a call to a different function between the calls to test1 and test2, or test1 and test2 having stack frames of different sizes.

Also, you should take compiler optimizations into account, which could break things too. However, the more similar your functions are, the less chances there are that they will receive different optimization treatment.

Upvotes: 1

inquam
inquam

Reputation: 12942

Just because this works for one compiler doesn't mean that it will for all. How uninitialized variables are handled is undefined and one computer could very well init pointers to null etc without breaking any rules. So don't do this or rely on it. I have actually seen code that depended on functionality in mysql that was a bug. When that was fixed in later versions the program stopped working. My thoughts about the designer of that system I'll keep to myself.

In short, never rely on functionality that is not defined. If you knowingly use it for a specific function and you are prepared that an update to the compiler etc can break it and you keep an eye out for this at all times it might be something you could explain and live with. But most of the time this is far from a good idea.

Upvotes: 0

Gopi
Gopi

Reputation: 19874

What you have is undefined behavior.

printf("Element of struct undeclared : %d %d %d %c \'%s\'\n", p2.a, p2.b, p2.c, p2.d, p2.e);

The scope of the variable p2 is local to function test2() and as soon as you exit the function the variable is no more valid.

You are accessing uninitialized variables which will lead to undefined behavior.

The output what you see is not guaranteed at all times and on all platforms. So you need to get rid of the undefined behavior in your code.

Upvotes: 1

The data may or may not appear in test2. It depends on exactly how the program was compiled. It's more likely to work in a toy example like yours than in a real program, and it's more likely to work if you turn off compiler optimizations.

The language definition says that the local variable ceases to exist at the end of the function. Attempting to read the address where you think it was stored may or may produce a result; it could even crash the program, or make it execute some completely unexpected code. It's undefined behavior.

For example, the compiler might decide to put a variable in registers in one function but not in the other, breaking the alignment of variables on the stack. It can even do that with a big struct, splitting it into several registers and some stack — as long as you don't take the address of the struct it doesn't need to exist as an addressable chunk of memory. The compiler might write a stack canary on top of one of the variables. These are just possibilities at the top of my head.

C lets you see a lot behind the scenes. A lot of what you see behind the scenes can completely change from one production compilation or run to the next.

Understanding what's going on here is useful as a debugging skill, to understand where values that you see in a debugger might be coming from. As a programming technique, this is useless since you aren't making the computer accomplish any particular result.

Upvotes: 0

unwind
unwind

Reputation: 400069

Of course there's a chance you can get corrupted data; you're using undefined behavior.

Upvotes: 1

Related Questions