I know of at least one implementation that uses dynamic memory
allocations (i.e. allocations from the "heap", what ever that is) to
build function activation records. Each activation record contains
enough storage for all the function's automatic variables, with each
variable preallocated within the record. No stack here; just a linked-
list of memory blocks malloc()ed by the underlying implementation.
How often do you add or remove a link other than at the
most-recently-accessed end?
Smells like a stack to me.
As the language does not have support for that sort of thing (as you
wisely note), there isn't much use in discussing hypotheticals. I
could say that hypothetically, such a function could take a complete
checkpoint of the program and its environment, order a ram upgrade
from Best Buy, and perform an orderly shutdown of the computer such
that the startup after Best Buy installs more ram would permit the
program to resume from where it left off. Just as possible, I guess,
as your suggestion
Just as possible, and perhaps less likely to need a second-level
failure handler to handle inability of the recovery routine to make
more memory accessible (at which point there's not much more that can
be done other than logging the failure and aborting), but it would be
rather harder to implement entirely in software.
Note that the first example I gave is not merely hypothetical; it HAS
BEEN implemented in a real system (at the OS level - it's not exclusive
to the C implementation) that runs on a large number of computers,
including millions of desktops.
In any case, if we stipulate a "stack", then a "stack overflow" is
pretty much an irrecoverable situation.
This must be some new meaning of the word "stack" with which I am not
familiar.
A stack is a data structure that allows you to insert data, and to
remove the most-recently-inserted not-yet-removed data element; you can
run out of memory to put the data you try to insert, but the idea of
"overflowing" the stack itself doesn't make sense.
And if we stipulate something
other than a stack, we recognize that C does not have the ability to
explicitly, programmattically, manipulate that data structure. Again,
the best such an intercept could do
....without knowing more about the system than that it's a conforming
hosted C implementation...
is perform an orderly shutdown.
Which can be rather difficult to do without being able to allocate
automatic storage, though probably not harder than "prohibitively
expensive", and certainly worth doing in applications where being able
to fail cleanly is important enough. I'm not sure you'd be able to do
even that without knowing more about the system than that it's a
conforming C implementation, though.
Or it can use knowledge about the implementation (whether in a C
program tied to that implementation or built into the implementation
itself) to recover from the failure and keep going.
Having said that, the signal() functions come to mind; the draft
standard doesn't indicate whether the inability to allocate an
automatic variable would raise a signal (like SIGILL, or SIGSEGV) or
not, but if it did, then a signal handler function could intercept the
signal and take appropriate (limited) action.
Using a guard page at the end of a contiguous block of memory would be
isomorphic to handling SIGSEGV, though that's not the mechanism that
the implementation I referred to uses.
If the program knows how to set up the guard page mechanism and
identify whether the SIGSEGV applies to that or to something else, it
could probably implement the actual recovery using only two or three
system-specific calls. (In fact, I'd expect that's what the OS handler
does if it's handled at the OS level: Call a recovery routine written
to use kernel calls and compiled with a C compiler.)
dave