[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
scratch/handler-bind c89b234405f 08/10: eval.c: Add new var `lisp-eval-d
From: |
Stefan Monnier |
Subject: |
scratch/handler-bind c89b234405f 08/10: eval.c: Add new var `lisp-eval-depth-reserve` |
Date: |
Thu, 28 Dec 2023 01:17:41 -0500 (EST) |
branch: scratch/handler-bind
commit c89b234405f8fa6c52f83104a46a4a2c3121198f
Author: Stefan Monnier <monnier@iro.umontreal.ca>
Commit: Stefan Monnier <monnier@iro.umontreal.ca>
eval.c: Add new var `lisp-eval-depth-reserve`
Rather than blindly increase `max-lisp-eval-depth` when entering the
debugger or running `signal-hook-function`, use this new "reserve"
to keep track of how much we have grown the stack for "debugger"
purposes so that for example recursive calls to `signal-hook-function`
can't eat up the whole C stack.
* src/eval.c (max_ensure_room): Rewrite.
(restore_stack_limits): Move before `max_ensure_room`. Rewrite.
(call_debugger, signal_or_quit): Adjust calls accordingly.
Also grow `max-lisp-eval-depth` for `hander-bind` handlers.
(init_eval_once): Don't initialize `max_lisp_eval_depth` here.
(syms_of_eval): Initialize it here instead.
Add new var `lisp-eval-depth-reserve`.
* doc/lispref/eval.texi (Eval): Add `lisp-eval-depth-reserve`.
---
doc/lispref/eval.texi | 17 +++++++++++++---
etc/NEWS | 5 +++++
src/eval.c | 55 ++++++++++++++++++++++++++++++---------------------
3 files changed, 51 insertions(+), 26 deletions(-)
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index 8af0ee49d02..45c892ad5a7 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -844,11 +844,22 @@ function body forms, as well as explicit calls in Lisp
code.
The default value of this variable is 1600. If you set it to a value
less than 100, Lisp will reset it to 100 if the given value is
-reached. Entry to the Lisp debugger increases the value, if there is
-little room left, to make sure the debugger itself has room to
-execute.
+reached.
@end defopt
+@defopt lisp-eval-depth-reserve
+In order to be able to debug infinite recursion errors, Entry to the
+Lisp debugger increases temporarily the value of
+@code{max-lisp-eval-depth}, if there is little room left, to make sure
+the debugger itself has room to execute. The same happens when
+running the handler of a @code{handler-bind}.
+
+The variable @code{lisp-eval-depth-reserve} bounds the extra depth
+that Emacs can add to @code{max-lisp-eval-depth} for those
+exceptional circumstances.
+@end defopt
+
+
@defvar values
The value of this variable is a list of the values returned by all the
expressions that were read, evaluated, and printed from buffers
diff --git a/etc/NEWS b/etc/NEWS
index b2a7c98ddda..014c32b4d8e 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1361,6 +1361,11 @@ values.
* Lisp Changes in Emacs 30.1
++++
+** New variable 'lisp-eval-depth-reserve'.
+It puts a limit to the amount by which Emacs can temporarily increase
+'max-lisp-eval-depth' when handling signals.
+
+++
** New special form 'handler-bind'.
Provides a functionality similar to `condition-case` except it runs the
diff --git a/src/eval.c b/src/eval.c
index b2b110da15b..67cd6efe6eb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -212,7 +212,6 @@ void
init_eval_once (void)
{
/* Don't forget to update docs (lispref node "Eval"). */
- max_lisp_eval_depth = 1600;
Vrun_hooks = Qnil;
pdumper_do_now_and_after_load (init_eval_once_for_pdumper);
}
@@ -248,22 +247,29 @@ init_eval (void)
redisplay_deep_handler = NULL;
}
-/* Ensure that *M is at least A + B if possible, or is its maximum
- value otherwise. */
-
static void
-max_ensure_room (intmax_t *m, intmax_t a, intmax_t b)
+restore_stack_limits (Lisp_Object data)
{
- intmax_t sum = ckd_add (&sum, a, b) ? INTMAX_MAX : sum;
- *m = max (*m, sum);
+ intmax_t old_depth;
+ integer_to_intmax (data, &old_depth);
+ lisp_eval_depth_reserve += max_lisp_eval_depth - old_depth;
+ max_lisp_eval_depth = old_depth;
}
-/* Unwind-protect function used by call_debugger. */
+/* Try and ensure that we have at least B dpeth available. */
static void
-restore_stack_limits (Lisp_Object data)
+max_ensure_room (intmax_t b)
{
- integer_to_intmax (data, &max_lisp_eval_depth);
+ intmax_t sum = ckd_add (&sum, lisp_eval_depth, b) ? INTMAX_MAX : sum;
+ intmax_t diff = min (sum - max_lisp_eval_depth, lisp_eval_depth_reserve);
+ if (diff <= 0)
+ return;
+ intmax_t old_depth = max_lisp_eval_depth;
+ max_lisp_eval_depth += diff;
+ lisp_eval_depth_reserve -= diff;
+ /* Restore limits after leaving the debugger. */
+ record_unwind_protect (restore_stack_limits, make_int (old_depth));
}
/* Call the Lisp debugger, giving it argument ARG. */
@@ -274,16 +280,12 @@ call_debugger (Lisp_Object arg)
bool debug_while_redisplaying;
specpdl_ref count = SPECPDL_INDEX ();
Lisp_Object val;
- intmax_t old_depth = max_lisp_eval_depth;
/* The previous value of 40 is too small now that the debugger
prints using cl-prin1 instead of prin1. Printing lists nested 8
deep (which is the value of print-level used in the debugger)
currently requires 77 additional frames. See bug#31919. */
- max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
-
- /* Restore limits after leaving the debugger. */
- record_unwind_protect (restore_stack_limits, make_int (old_depth));
+ max_ensure_room (100);
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
@@ -1802,16 +1804,13 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object
data, bool keyboard_quit)
/* This hook is used by edebug. */
if (! NILP (Vsignal_hook_function)
- && ! NILP (error_symbol)
- /* Don't try to call a lisp function if we've already overflowed
- the specpdl stack. */
- && specpdl_ptr < specpdl_end)
+ && ! NILP (error_symbol))
{
- /* Edebug takes care of restoring these variables when it exits. */
- max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20);
-
+ specpdl_ref count = SPECPDL_INDEX ();
+ max_ensure_room (20);
/* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */
call2 (Vsignal_hook_function, error_symbol, data);
+ unbind_to (count, Qnil);
}
conditions = Fget (real_error_symbol, Qerror_conditions);
@@ -1849,9 +1848,12 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object
data, bool keyboard_quit)
Lisp_Object error_data
= (NILP (error_symbol)
? data : Fcons (error_symbol, data));
+ specpdl_ref count = SPECPDL_INDEX ();
+ max_ensure_room (20);
push_handler (make_fixnum (skip + h->bytecode_dest),
SKIP_CONDITIONS);
call1 (h->val, error_data);
+ unbind_to (count, Qnil);
pop_handler ();
}
continue;
@@ -1901,8 +1903,8 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object
data, bool keyboard_quit)
&& NILP (Vinhibit_debugger)
&& !NILP (Ffboundp (Qdebug_early)))
{
- max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
specpdl_ref count = SPECPDL_INDEX ();
+ max_ensure_room (100);
AUTO_STRING (redisplay_trace, "*Redisplay-trace*");
Lisp_Object redisplay_trace_buffer;
AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace*
*/
@@ -4345,6 +4347,13 @@ actual stack overflow in C, which would be fatal for
Emacs.
You can safely make it considerably larger than its default value,
if that proves inconveniently small. However, if you increase it too far,
Emacs could overflow the real C stack, and crash. */);
+ max_lisp_eval_depth = 1600;
+
+ DEFVAR_INT ("lisp-eval-depth-reserve", lisp_eval_depth_reserve,
+ doc: /* Extra depth that can be allocated to handle errors.
+This is the max depth that the system will add to `max-lisp-eval-depth'
+when calling debuggers or `handler-bind' handlers. */);
+ lisp_eval_depth_reserve = 200;
DEFVAR_LISP ("quit-flag", Vquit_flag,
doc: /* Non-nil causes `eval' to abort, unless `inhibit-quit' is
non-nil.
- branch scratch/handler-bind created (now 26b7078705a), Stefan Monnier, 2023/12/28
- scratch/handler-bind 89a298b3d2f 02/10: Fix ert-tests.el for the new `handler-bind` code, Stefan Monnier, 2023/12/28
- scratch/handler-bind dcf7508c947 04/10: emacs-module-tests.el (mod-test-non-local-exit-signal-test): Repair test, Stefan Monnier, 2023/12/28
- scratch/handler-bind 1c1d2eb3e38 03/10: Use handler-bind to repair bytecomp-tests, Stefan Monnier, 2023/12/28
- scratch/handler-bind 6a57b9151b1 06/10: Move batch backtrace code to `top_level_2`, Stefan Monnier, 2023/12/28
- scratch/handler-bind ae21819496a 01/10: ert.el: Use `handler-bind` to record backtraces, Stefan Monnier, 2023/12/28
- scratch/handler-bind 26b7078705a 10/10: (backtrace-on-redisplay-error): Use `handler-bind`, Stefan Monnier, 2023/12/28
- scratch/handler-bind b925152bffc 09/10: (signal_or_quit): Preserve error object identity, Stefan Monnier, 2023/12/28
- scratch/handler-bind 917596160c1 05/10: startup.el: Use `handler-bind` to implement `--debug-init`, Stefan Monnier, 2023/12/28
- scratch/handler-bind 634bf619476 07/10: (macroexp--with-extended-form-stack): Use plain `let`, Stefan Monnier, 2023/12/28
- scratch/handler-bind c89b234405f 08/10: eval.c: Add new var `lisp-eval-depth-reserve`,
Stefan Monnier <=