LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   returning address of stack variable in function (https://www.linuxquestions.org/questions/programming-9/returning-address-of-stack-variable-in-function-4175668319/)

barunparichha 01-23-2020 07:51 PM

returning address of stack variable in function
 
In function fun, address of stack variable(a) is copied to ptr.
But as soon as program control comes out of function, stack variables gets cleaned.
So inside main(), program should not have printed value of a.

But here, I am able to print the content inside main().
Is this expected ?

Code:

#include<stdio.h>
 
int* fun(int *ptr)
{
    int a=40;
    ptr=&a;
    return ptr;
}

int main()
{
    int i=20;
    int *ptr=&i;
    printf("\n %d",*fun(ptr));
    return 0;
}

Result:
Code:

./a.out
40


BW-userx 01-23-2020 09:11 PM

humm
Code:

#include<stdio.h>
 
int* fun(int *ptr)
{
        printf("in fun ptr = %d before reassignment \n", *ptr);
    int a=40;
    // you are not assigning the prams ptr
    //your assigning 'a' to ptr over riding your pram ptr
    //so it is returning 40 like you programmed it to do.
    ptr=&a;
    printf("in fun a = %d ptr = %d\n",a, *ptr);
   
    return ptr;
}
int* fun2(int *ptr) { return ptr; }

int main()
{
    int i=20;
    int *ptr=&i;
    printf("main ptr = %d\n", *ptr);
   
    //your function is printing what is declared
    // in your function
    printf("in main\n %d\n\n",*fun(ptr));

    int *f, s;
    s = 32;
    f = &s;
    printf("fun2= %d\n", *fun2(f));
    return 0;
}

results
Code:

$ ./a.out
main ptr = 20
in fun ptr = 20 before reassignment
in fun a = 40 ptr = 40
in main
 40

fun2= 32


NevemTeve 01-23-2020 09:40 PM

@OP: What you see is accidental working, but what you should achieve is reliable working.
The memory on the stack might not have been overwritten that moment, but sooner or later it will be overwritten, and your data will be lost. Also stack is allowed to grow and shrink on demand, so a pointer that points to a currently unused stack-area might become invalid pointer that causes segmentation fault when you try to use the pointed value.

rtmistler 01-23-2020 09:48 PM

Quote:

Originally Posted by barunparichha (Post 6082251)
In function fun, address of stack variable(a) is copied to ptr.
But as soon as program control comes out of function, stack variables gets cleaned.
So inside main(), program should not have printed value of a.

But here, I am able to print the content inside main().
Is this expected ?

Just because the stack gets popped, does not mean that the locations used by it are corrupt, in fact they typically are not until you make another function call. This does not mean that you're doing a correct thing. You shouldn't be returning a stack variable address to the calling function.

Your code is the reverse of how I'd pass a pointer and use it, crude example. I'd likely check for a NULL pointer and return a status from fun(), neither of which is done here:
Code:

#include <stdio.h>

void fun(int *ptr)
{
    *ptr = 20;
}

void main()
{
    int i=0;
    printf("Original value: %d\n", i);
    fun(&i);
    printf("New Value: %d\n", i);
}


Geist 01-23-2020 10:04 PM

This is playing the lottery.
Might work right now, might stop working if you use a different (version of the ) compiler, different optimizations, etc.

It's like using uninitialized variables.
Some hypothetical int in a different code might be initialized 'by itself' to 0x00000000 to you, might do it to 0xdeadbeef for someone else, or yourself at another compilation.

BW-userx 01-23-2020 10:16 PM

more pointer math?
Code:

#include<stdio.h>
 
int* fun2(int *ptr)
{
        return ptr;
}
int* fun3(int *ptr) {
        int a = 10, g = 0;
        g = *ptr;
        *ptr=(a+g);
        return ptr;
}

int main()
{
     
    int *f, s;
    s = 32;
    f = &s;
 
    printf("fun2= %d\n", *fun2(f));
    printf("fun3= %d\n", *fun3(f));
    return 0;
}

resutls
Code:

$ ./a.out
fun2= 32
fun3= 42


barunparichha 01-24-2020 12:12 AM

Conclusion:
==============
1. such results are compiler specific.
2. so even after stack unwinding, variables take some time to cleanup.

SoftSprocket 01-24-2020 07:41 AM

Quote:

Originally Posted by barunparichha (Post 6082308)
Conclusion:
==============
1. such results are compiler specific.
2. so even after stack unwinding, variables take some time to cleanup.

They don't really cleanup. When a function returns the portion of the stack that it has used is available for other uses. That means the results from continuing to access it in your program are undefined. Amongst the possible outcomes of using a pointer to a function local variable after the function has terminated is that you get the value assigned.

Memory assigned with malloc is allocated on the heap and until freed will remain available to your program so a pointer can be assigned to and returned from a function and safely used. A pointer to a local variable can be passed to a function and assigned then read after the function returns because it is on the calling functions stack, not the receiving function.

dugan 01-24-2020 08:07 AM

Huh. This prints out a warning:

Code:

#include <stdio.h>

int *fun()
{
    int a;
    a = 40;
    return &a;
}

int main()
{
    printf("%d\n", *fun());
    return 0;
}

Code:

stack2.c: In function ‘fun’:
stack2.c:7:12: warning: function returns address of local variable [-Wreturn-local-addr]
    7 |    return &a;
      |            ^~

But this does not:

Code:

#include <stdio.h>

int *fun()
{
    int a;
    int *b;
    b = &a;
    return b;
}

int main()
{
    printf("%d\n", *fun());
    return 0;
}

I guess the compiler just isn't smart enough to catch it when it's a pointer.

And clang-check didn't catch it either.

rtmistler 01-24-2020 08:07 AM

Quote:

Originally Posted by barunparichha (Post 6082308)
Conclusion:
==============
1. such results are compiler specific.
2. so even after stack unwinding, variables take some time to cleanup.

Also in agreement with SoftSprocket's comment. You seem have misnomers about things like the stack, the heap, and how programs use them.

What would be helpful here is what you're trying to figure out or learn. Results are system specific and the stack is not cleaned up.

Why did you write that program initially, and what were you intending to explore/learn?

dugan 01-24-2020 08:20 AM

Let this be a lesson about the benefits of modern C/C++ tooling.

Code:

❯ cat stack3.c
#include <stdio.h>

int *fun()
{
    int a;
    int *b;
    b = &a;
    return b;
}

int main()
{
    printf("%d\n", *fun());
    return 0;
}
❯ cat Makefile
stack3.o:
        gcc -o stack3.o stack3.c
❯ bear make
gcc -o stack3.o stack3.c
❯ clang-tidy stack3.c
2 warnings generated.
stack3.c:8:5: warning: Address of stack memory associated with local variable 'a' returned to caller [clang-analyzer-core.StackAddrEscapeBase]
    return b;
    ^
stack3.c:13:21: note: Calling 'fun'
    printf("%d\n", *fun());
                    ^
stack3.c:8:5: note: Address of stack memory associated with local variable 'a' returned to caller
    return b;
    ^
stack3.c:13:5: warning: 2nd function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage]
    printf("%d\n", *fun());
    ^
stack3.c:13:21: note: Calling 'fun'
    printf("%d\n", *fun());
                    ^
stack3.c:5:5: note: 'a' declared without an initial value
    int a;
    ^
stack3.c:13:21: note: Returning from 'fun'
    printf("%d\n", *fun());
                    ^
stack3.c:13:5: note: 2nd function call argument is an uninitialized value
    printf("%d\n", *fun());
    ^

I wrote a Makefile as an intermediate step towards generating the compilation database (compile_commands.json) needed to get clang's tooling to work, then I ran bear on that Makefile to generate said database. And then I ran the code through clang-tidy. That caught it.

bigearsbilly 01-30-2020 06:27 AM

i always find it more beneficial to concentrate on studying good code, not bad.


All times are GMT -5. The time now is 05:05 PM.