[ Home ]
SBCL Internals

The pages on this CLiki-driven site can be edited by anybody at any time. No warranty of any kind can therefore be made; any implied warranties of merchantability or fitness for a particular purpose are expressly disclaimed
[ Home ] [ Recent Changes ] [ About CLiki ] [ Text Formatting ]

Here's what one user understands of the current intended stack exhaustion handling scheme on x86 (circa 5 October 2004, SBCL version 0.8.15). I think it's pretty similar on other platforms, but maybe not.

Here's the intended behavior: when the control stack is exhausted, e.g., by something like this:

* (defun foo () (foo))
FOO
* (foo)

a Lisp error is signalled, dropping the user into the Lisp debugger.

At least on x86 the only restarts there will basically return you to the toplevel, but you can do a little more; not much, because the debugger will be running at the top of the exhausted control stack.

Here's how the sbcl runtime implements this on x86:

  1. The Lisp control stack is the C control stack on x86.

  2. When the runtime starts up, it mprotects (read/exec) a page at the top of the stack's space. This page is called the control_stack_guard_page.

  3. Also at start time, the runtime installs some signal handlers, including a handler for whatever signal is generated on trying to write to a read-only page (SIGSEGV on Linux, NetBSD, OpenBSD; SIGBUS on FreeBSD; let's call it "memory fault" from here on). The same memory fault signal handler is used for at least 3 purposes: stack exhaustion, return from stack exhaustion, and heap exhaustion (the last is for gc triggering, though that's not due to writes to mprotected pages). Using the signal handler for dealing with return from stack exhaustion was added within the last month (ca. 5 October 2004). It's present at least by sbcl version 0.8.14.24.

  4. Also at start time, the runtime calls sigaltstack and sigaction to direct the operating system to run the memory fault signal handler on the alternate signal stack when the memory fault signal is delivered. Space for the alternate signal stack is allocated, too.

  5. When execution reaches the top of the control stack, Lisp tries to write in the control_stack_guard_page. The operating system generates a memory fault signal. The signal handler, running on the alternate stack, checks the fault address to determine whether the fault is due to stack exhaustion or other things. In this case, the fault address is in the control_stack_guard_page, so the fault is due to stack exhaustion. Now the signal handler does the following:

  6. When the user decides to exit the debugger (by breaking out of the call that exhausted the stack), the control stack will shrink, involving a write to the control_stack_return_guard_page, the page that was mprotect'ed (read/exec) in 5b. This will generate a memory fault. The signal handler will identify where the fault address is. Because the fault address is in the control_stack_return_guard_page, the signal handler will

    This use of the memory fault handler is meant to ensure that the control_stack_guard_page gets re-protected after exiting the debugger. In SBCL 0.8.14, this was being done in the Lisp repl.


This is falls into the runtime category, however that works.

This page is linked from: Signal Handling  

CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively