0

Inspired by this related SO answer, I am trying to obtain stack memory usage (as distinct from heap memory) on Linux Debian 9, without much success. I have created some testing code that doesn't produce expected results:

size_t top_of_stack = 0;

int main(void) {
    int x = 0;
    top_of_stack = (size_t) &x;
    printf("Top of stack in main(): %lu\n", top_of_stack);
    int y = 0;
    size_t ss1 = (size_t) &y;
    printf("Top of stack in main() ss1: %lu\n", ss1);
    printf("Diff in main() top - ss1: %lu\n", top_of_stack - ss1);
    long z = 0;
    size_t ss2 = (size_t) &z;
    printf("Top of stack in main() ss2: %lu\n", ss2);
    printf("Diff in main() ss1 - ss2: %lu\n", ss1 - ss2);
    double dd1[100];
    dd1[99] = 12.0;
    dd1[98] = 121.0;
    dd1[97] = 122.0;
    size_t ss3 = (size_t) &(dd1[99]);
    printf("Top of stack in main() ss3: %lu\n", ss3);
    printf("Diff in main() ss2 - ss3: %lu\n", ss2 - ss3);
    return 0;
}

The printout:

Top of stack in main(): 140733255163788
Top of stack in main() ss1: 140733255163784
Diff in main() top - ss1: 4
Top of stack in main() ss2: 140733255163776
Diff in main() ss1 - ss2: 8
Top of stack in main() ss3: 140733255163768
Diff in main() ss2 - ss3: 8

Of the three "Diff" printouts, only the first seems correct. The second does not account for the fact that two long variables have been created (long z and size_t ss1), not one. The third "Diff" report doesn't account for the fact that an array of 100 doubles has been created, with the last three items assigned values.

How can this be made to work?

Note that although I am able to include the "alloc.h" header on my system, the stackavail() function is not available. This is the reason I am trying to develop my own solution.

Theo d'Or
  • 783
  • 1
  • 4
  • 17
  • 3
    It can't be made to work. The stack layout is determined by the compiler. The variables can be in any order, and there may be any amount of padding before, between, and after the variables. – user3386109 Apr 14 '21 at 19:58
  • 1
    If you never use the address of a variable, the compiler may decide to keep it in a register and not allocate any memory for it. That's probably happening for the `size_t` variables. – Barmar Apr 14 '21 at 19:59
  • Why are you expecting `top_of_stack` to be in the stack at all? It's a global variable, it should be in the data segment. – Barmar Apr 14 '21 at 20:01
  • Check the generated assembly code. – Barmar Apr 14 '21 at 20:03
  • @OP I have no clue what problem you're trying to solve. – Cheatah Apr 14 '21 at 20:04
  • 1
    @Barmar The `top_of_stack` variable is just to track the stack value, it isn't meant to be in the stack. It's there really because I started by following the code presented in the linked related answer. Regarding your 'assembly code' comment, what are you driving at? My knowledge of assembly is close to nil. – Theo d'Or Apr 14 '21 at 20:05
  • If you need to understand low-level implementation details like this, you'll probably have to learn enough to understand it -- you don't need to be able to write it. – Barmar Apr 14 '21 at 20:06
  • @Barmar What you're saying is true, but learning how to write it is actually a great way to learn how it works. – klutt Apr 14 '21 at 20:07
  • I suppose you could grab the value of the stack pointer using in-line assembly. But to do that, you would need to understand assembly. – user3386109 Apr 14 '21 at 20:52
  • @user3386109 Isn't my code attempting that already, getting the value of the stack pointer? I guess what you're implying is that the "stack pointer" and the last variable pointer created on the stack are not the same thing. Regarding assembly solutions, I have seen some, but none that I could copy and use as is. The assembly involved though was minimal, one line reading a value. Please feel free to write up an answer if you can present a working solution (for Linux, GCC compiler). – Theo d'Or Apr 14 '21 at 21:35
  • Try searching for `[c] inline assembly stack pointer` and see what you get. – user3386109 Apr 14 '21 at 21:46

1 Answers1

4

C does not make any guarantees about stack layout. As far as the compiler is concerned, it can add or remove variables any way it likes as long as it does not affect the observable behavior. It can also introduce padding in any way it want.

I don't know of any way to do this in an exact manner. But if you just need a quick estimate that does not need to be computed during runtime, just sum up all the local variables. It will not be exact, and probably a little bit below the real value because of padding and other stuff.

But comparing pointers is a bad idea. If you have two pointers, void *p, *q; then the operation p-q is meaningless, unless p and q points to the same object. The operation is actually likely to invoke undefined behavior. This answer explains it.

klutt
  • 30,332
  • 17
  • 55
  • 95