Keep in mind that this is just for thread stacks - you can set the size for them yourself, so ideally you'd always do it. Then a guaranteed minimum size becomes irrelevant.
Keep in mind that this is just for thread stacks - you can set the size for them yourself, so ideally you'd always do it. Then a guaranteed minimum size becomes irrelevant.
How does a normal working programmer calculate the size of each of their stack frames? I'm a compiler researcher and I'd struggle to do that. How are application developers going to do it?
And how do you design a program to have a deterministic maximum call stack depth?
I don't think these things are as easy as you're making out.
I know that in the small-embedded world, people do work on such things.
In those leaf functions you can check &local_var and compare it to pthread_attr_getstack(pthread_getattr_np()). (Of course that's not precise for many reasons.)
> And how do you design a program to have a deterministic maximum call stack depth?
If you're running only your code - don't use recursion, or alloca. If you use external libraries, you have to research what they do and add some extra in case of updates.
Bounded stack size is also a common issue if you're targeting small microprocessors.
For non-critical apps it should be pretty easy to figure out the needed stack size. For cases when you want to guarantee it... that gets more tricky.
Edit: just learned that clang has the option -fstack-usage which should help a lot.
Or you can try to figure out the maximum number of times it'll recurse: for example, the height of a red-black tree with less than 2^64 nodes is less than 128, iirc.
I remember one day in the 90s counting out like max address len and max zip code len and so and trying to figure out how long to make my target stack allocated buffer, and i was like fuck it, I have more important things to do, all my stack buffers are hence forth 65536 bytes long.
I tried googling for how SPARK Ada provides assurances against exceeding stack-size limits, but I couldn't find a decent answer. I presume it does so, though.
edit: forgot about alloca
edit 2: Turns out the AdaCore folks have a tool specifically for static analysis of stack-space requirements of Ada/C/C++ code: https://www.adacore.com/gnatpro/toolsuite/gnatstack
For total depth, keeping you program simple and predictable helps. People certainly manage to do it even for large programs like Linux itself, where stack size is like 16KiB or so. https://elixir.bootlin.com/linux/v5.2/source/arch/x86/includ... and less on other archs. 8 KiB on arm https://elixir.bootlin.com/linux/v5.13-rc7/source/arch/arm/i...
If I tell you as a compiler writer that this loop body from this function, but with this branch and this branch outlined, but only when called from this context, takes n bytes... I don't get what most working programmers are going to usefully do with that information.
If the language is complicated and has generics or whatever, the programmer will have to do more work to understand it.
It's not a huge issue in C.
If you ask a compiler how much stack a function will use the answer for a non-trivial compiler for a complicated language is always going to be 'it depends...'
The only use case is for real-time embedded code -typically in aerospace- where the coding guidelines prohibits you from using any recursion at all and you have to prove the highest stack usage fits into the chosen microcontroller.
On exit just scan from the maximum stack to minimum looking for non-zero.
If you have tests it should be easy to get within a few bytes of max stack used, which is probably just as good as instrumenting everything.
Sure, that could happen.
But what the other guy was saying about being a compiler developer and being unsure how to calculate the maximum depth is that there are many, many ways to arrive at the wrong result. Resursion, argv/envp, varags, alloca, and so on. So unless you are going to spend a great deal of energy proving maximum depth you're going to be using an estimate of some sort. Thus, 'probably just as good'.