;;;; -*- coding: utf-8; fill-column: 78 -*-
+changes in sbcl-1.0.26 relative to 1.0.25:
+ * new feature: runtime option --disable-ldb
+ * new feature: runtime option --lose-on-corruption to die at the
+ slightest hint of possibly non-recoverable errors: running out of
+ memory, stack, alien stack, binding stack, encountering a memory
+ fault, etc. In the absence of --lose-on-corruption a warning is
+ printed to stderr.
+
changes in sbcl-1.0.25 relative to 1.0.24:
* incompatible change: SB-INTROSPECT:FUNCTION-ARGLIST is deprecated, to be
removed later. Please use SB-INTROSPECT:FUNCTION-LAMBDA-LIST instead.
cleanly in Unix pipelines. See also the @code{--noprint} and
@code{--disable-debugger} options.
+@item --disable-ldb
+Disable the low-level debugger. Only effective if SBCL is compiled
+with LDB.
+
+@item --lose-on-corruption
+There are some dangerous low level errors (for instance, control stack
+exhausted, memory fault) that (or whose handlers) can corrupt the
+image. By default SBCL prints a warning, then tries to continue and
+handle the error in Lisp, but this will not always work and SBCL may
+malfunction or even hang. With this option, upon encountering such an
+error SBCL will invoke ldb (if present and enabled) or else exit.
+
@item --script @var{filename}
As a runtime option this is equivalent to @code{--noinform}
+@code{--disable-ldb} @code{--lose-on-corruption}
@code{--end-runtime-options} @code{--script} @var{filename}. See the
description of @code{--script} as a toplevel option below.
cleanly in Unix pipelines. See also the "\-\-noprint" and
"\-\-disable\-debugger" options.)
.TP 3
+.B \-\-disable\-ldb
+Disable the low-level debugger. Only effective if SBCL is compiled with LDB.
+.TP 3
+.B \-\-lose\-on\-corruption
+There are some dangerous low level errors (for instance, control stack
+exhausted, memory fault) that (or whose handlers) can corrupt the
+image. By default SBCL prints a warning, then tries to continue and
+handle the error in Lisp, but this will not always work and SBCL may
+malfunction or even hang. With this option, upon encountering such an
+error SBCL will invoke ldb (if present and enabled) or else exit.
+.TP 3
.B \-\-script <filename>
-As a runtime option equivalent to \-\-noinform
-\-\-end\-toplevel\-options \-\-script <filename>. See the description
-of \-\-script as a toplevel option below.
+As a runtime option equivalent to \-\-noinform \-\-disable\-ldb
+\-\-lose\-on\-corruption \-\-end\-toplevel\-options \-\-script
+<filename>. See the description of \-\-script as a toplevel option
+below.
.TP 3
.B \-\-help
Print some basic information about SBCL, then exit.
This option disables the debugger, causing errors to print a backtrace
and exit with status 1 instead -- which is a mode of operation better suited
for batch processing. See the User Manual on \f(CRSB\-EXT:DISABLE\-DEBUGGER\fR for details.
+.TP 3
.B \-\-script <filename>
Implies \-\-no-sysinit \-\-no-userinit \-\-disable-debugger
\-\-end\-toplevel\-options.
echo //doing warm init - compilation phase
./src/runtime/sbcl \
--core output/cold-sbcl.core \
+--lose-on-corruption \
--no-sysinit --no-userinit < make-target-2.lisp
echo //doing warm init - load and dump phase
./src/runtime/sbcl \
--core output/cold-sbcl.core \
+--lose-on-corruption \
--no-sysinit --no-userinit < make-target-2-load.lisp
SBCL_PWD=`echo $SBCL_PWD | sed s/\ /\\\\\\\\\ /g`
fi
-SBCL="$SBCL_PWD/src/runtime/sbcl --noinform --core $SBCL_PWD/output/sbcl.core --disable-debugger --no-sysinit --no-userinit"
+SBCL="$SBCL_PWD/src/runtime/sbcl --noinform --core $SBCL_PWD/output/sbcl.core \
+--lose-on-corruption --disable-debugger --no-sysinit --no-userinit"
SBCL_BUILDING_CONTRIB=1
export SBCL SBCL_BUILDING_CONTRIB
void
gc_heap_exhausted_error_or_lose (long available, long requested)
{
+ struct thread *thread = arch_os_get_current_thread();
/* Write basic information before doing anything else: if we don't
* call to lisp this is a must, and even if we do there is always
* the danger that we bounce back here before the error has been
/* If we are in GC, or totally out of memory there is no way
* to sanely transfer control to the lisp-side of things.
*/
- struct thread *thread = arch_os_get_current_thread();
print_generation_stats(1);
fprintf(stderr, "GC control variables:\n");
fprintf(stderr, " *GC-INHIBIT* = %s\n *GC-PENDING* = %s\n",
else {
/* FIXME: assert free_pages_lock held */
(void)thread_mutex_unlock(&free_pages_lock);
+ gc_assert(get_pseudo_atomic_atomic(thread));
+ clear_pseudo_atomic_atomic(thread);
+ if (get_pseudo_atomic_interrupted(thread))
+ do_pending_interrupt();
+ /* Another issue is that signalling HEAP-EXHAUSTED error leads
+ * to running user code at arbitrary places, even in a
+ * WITHOUT-INTERRUPTS which may lead to a deadlock without
+ * running out of the heap. So at this point all bets are
+ * off. */
+ if (SymbolValue(INTERRUPTS_ENABLED,thread) == NIL)
+ corruption_warning_and_maybe_lose
+ ("Signalling HEAP-EXHAUSTED in a WITHOUT-INTERRUPTS.");
funcall2(StaticSymbolFunction(HEAP_EXHAUSTED_ERROR),
alloc_number(available), alloc_number(requested));
lose("HEAP-EXHAUSTED-ERROR fell through");
lossage_handler = default_lossage_handler;
}
-void
-lose(char *fmt, ...)
+static
+void print_message(char *fmt, va_list ap)
{
- va_list ap;
- fprintf(stderr, "fatal error encountered in SBCL pid %d",getpid());
+ fprintf(stderr, " in SBCL pid %d",getpid());
#if defined(LISP_FEATURE_SB_THREAD)
fprintf(stderr, "(tid %lu)", (unsigned long) thread_self());
#endif
if (fmt) {
fprintf(stderr, ":\n");
- va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
- va_end(ap);
}
fprintf(stderr, "\n");
- fflush(stderr);
+}
+
+static inline void
+call_lossage_handler() never_returns;
+
+static inline void
+call_lossage_handler()
+{
lossage_handler();
fprintf(stderr, "Argh! lossage_handler() returned, total confusion..\n");
exit(1);
}
+
+void
+lose(char *fmt, ...)
+{
+ va_list ap;
+ /* Block signals to prevent other threads, timers and such from
+ * interfering. If only all threads could be stopped somehow. */
+ block_blockable_signals();
+ fprintf(stderr, "fatal error encountered");
+ va_start(ap, fmt);
+ print_message(fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+ call_lossage_handler();
+}
+
+boolean lose_on_corruption_p = 0;
+
+void
+corruption_warning_and_maybe_lose(char *fmt, ...)
+{
+ va_list ap;
+ sigset_t oldset;
+ thread_sigmask(SIG_BLOCK, &blockable_sigset, &oldset);
+ fprintf(stderr, "CORRUPTION WARNING");
+ va_start(ap, fmt);
+ print_message(fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "The integrity of this image is possibly compromised.\n");
+ if (lose_on_corruption_p)
+ fprintf(stderr, "Exiting.\n");
+ else
+ fprintf(stderr, "Continuing with fingers crossed.\n");
+ fflush(stderr);
+ if (lose_on_corruption_p)
+ call_lossage_handler();
+ else
+ thread_sigmask(SIG_SETMASK,&oldset,0);
+}
\f
/* internal error handler for when the Lisp error system doesn't exist
*
#define _INTERR_H_
extern void lose(char *fmt, ...) never_returns;
+extern boolean lose_on_corruption_p;
+extern void corruption_warning_and_maybe_lose(char *fmt, ...);
extern void enable_lossage_handler(void);
extern void disable_lossage_handler(void);
extern void describe_internal_error(os_context_t *context);
os_context_t *context = arch_os_get_context(&void_context);
#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
os_restore_fp_control(context);
+#ifndef LISP_FEATURE_WIN32
+ if ((signal == SIGILL) || (signal == SIGBUS)
+#ifndef LISP_FEATURE_LINUX
+ || (signal == SIGEMT)
+#endif
+ )
+ corruption_warning_and_maybe_lose("Signal %d recieved", signal);
+#endif
#endif
interrupt_handle_now(signal, info, context);
}
* protection so the error handler has some headroom, protect the
* previous page so that we can catch returns from the guard page
* and restore it. */
+ corruption_warning_and_maybe_lose("Control stack exhausted");
protect_control_stack_guard_page(0);
protect_control_stack_return_guard_page(1);
* now -- some address is better then no address in this case.
*/
current_memory_fault_address = addr;
+ /* To allow debugging memory faults in signal handlers and such. */
+ corruption_warning_and_maybe_lose("Memory fault");
arrange_return_to_lisp_function(context,
StaticSymbolFunction(MEMORY_FAULT_ERROR));
}
/* other command line options */
boolean noinform = 0;
boolean end_runtime_options = 0;
+ boolean disable_lossage_handler_p = 0;
lispobj initial_function;
const char *sbcl_home = getenv("SBCL_HOME");
* TOPLEVEL-INIT sees the option. */
noinform = 1;
end_runtime_options = 1;
+ disable_lossage_handler_p = 1;
+ lose_on_corruption_p = 1;
break;
} else if (0 == strcmp(arg, "--noinform")) {
noinform = 1;
++n;
}
++argi;
+ } else if (0 == strcmp(arg, "--disable-ldb")) {
+ disable_lossage_handler_p = 1;
+ ++argi;
+ } else if (0 == strcmp(arg, "--lose-on-corruption")) {
+ lose_on_corruption_p = 1;
+ ++argi;
} else if (0 == strcmp(arg, "--end-runtime-options")) {
end_runtime_options = 1;
++argi;
define_var("nil", NIL, 1);
define_var("t", T, 1);
- enable_lossage_handler();
+ if (!disable_lossage_handler_p)
+ enable_lossage_handler();
globals_init();
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.25.20"
+"1.0.25.21"