5 ms·
Never thought about it but yes, what a huge (and easily implementable) oversight - stackSize(), stackUsed(), stackTopPtr() would be a few asm instructions in m
by QuadrupleA 5y ago
Never thought about it but yes, what a huge (and easily implementable) oversight - stackSize(), stackUsed(), stackTopPtr() would be a few asm instructions in most cases.
- lifthrasiir 5y agoAs mentioned in the OP though, there is zero guarantee about the stack usage by library functions.
- OskarS 5y agoNo, but that's a pretty weak argument not to have them: they're better than nothing. Not all code uses libraries. And if it was part of the C standard, libraries could use them as well: libraries could fail gracefully instead of blowing the stack. Many libraries already do this when malloc fails, after all.
- saagarjha 5y agoI have yet to see a library that fails gracefully when malloc fails. Many claim to be able to do so, but usually keel over when actually presented with a failure.
- PerkinWarwick 5y ago...or much of anything else. I've seen commercial libraries monkey with processor state in some nasty ways.
- nybble41 5y agoThere is also no guarantee that the stack is contiguous—see the "-fsplit-stack" GCC option, or search for "segmented stacks". Libraries for coroutines and delimited continuations also routinely segment the stack. A simple API based around easy access to "top of stack", "bottom of stack", and "current stack pointer" addresses is thus non-universal. There may not be a meaningful limit to the amount of stack available, aside from available heap memory or address space. And this can change over time in response to actions other than allocating or freeing memory on the stack.
- PerkinWarwick 5y agoIt seems to me that in the case of the x86, the virtual memory system could detect overrunning the end of the stack and announce it to you. The meta-problem is what to do with the information.
- masklinn 5y agoA clean / clear error would already be better than just segfaulting with no indication (that's why e.g. Ruby or Python have explicit stack depth check and will raise an exception hopefully before they run out of C stack).
- vasama 5y agoThere is no useful way to employ these functions. It's equivalent to asking if a mutex is locked. That piece of information is worthless.
- notact 5y agoIf writing a recursive algorithm on arbitrary input, check remaining stack size upon recursive function entry. If space is depleted, allocate a new fiber (aka a brand new clean stack), switch to it, and resume. Switch back to calling fiber on stack unwind.
- 10000truths 5y agoIf you’re writing a recursive algorithm on arbitrary input, you should be using a stack container to store your state, not the call stack.
- sydthrowaway 5y agoyou mean std::stack?
- notact 5y agoWhy do you think so? A stack container ordinarily contains a single data type. You can jump through some hoops to let it store completely arbitrary types, but when you consider a function's stack frame as a distinct type, the call stack naturally does that for you.
- kragen 5y agoMost commonly you handle this with a stack of records.
- 10000truths 5y ago1. A stack frame usually takes up far more memory than the state that actually needs to be persisted, due to local variables and padding from alignment requirements. With a stack container, you can specify exactly what gets stored, and save on your memory footprint. 2. There are very few knobs you can tweak to control how your call stack space is allocated or represented in memory. With a stack container, you have much finer control over that - you can do reallocations or define custom error handling when you overflow the container, you can deallocate/shrink the container when you no longer need the space, you can serialize the container to disk to make your processing resumable, etc. 3. A call stack has a very limited set of operations. You can only access data from the current stack frame, and you can only push/pop (call/return) stack frames. But with your own stack-like data structure, you could extend it to do far more, e.g. accessing data from the first or last n traversals, or insert/remove multiple elements at once.