aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2023-12-26 23:56:09 -0500
committerStefan Monnier2024-01-04 16:36:22 -0500
commit02edbc88a1210b8d5a3e62ca4f03ffd17b23cbf7 (patch)
treea37f8100646efe24a7224c947c7bc66ec4683c16
parenta5dcc1abea32abc906abfb66599c280b01d6ba27 (diff)
downloademacs-02edbc88a1210b8d5a3e62ca4f03ffd17b23cbf7.tar.gz
emacs-02edbc88a1210b8d5a3e62ca4f03ffd17b23cbf7.zip
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`.
-rw-r--r--doc/lispref/eval.texi19
-rw-r--r--etc/NEWS5
-rw-r--r--src/eval.c55
3 files changed, 53 insertions, 26 deletions
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index f4c99640143..b42020f43af 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -844,11 +844,24 @@ function body forms, as well as explicit calls in Lisp code.
844 844
845The default value of this variable is 1600. If you set it to a value 845The default value of this variable is 1600. If you set it to a value
846less than 100, Lisp will reset it to 100 if the given value is 846less than 100, Lisp will reset it to 100 if the given value is
847reached. Entry to the Lisp debugger increases the value, if there is 847reached.
848little room left, to make sure the debugger itself has room to
849execute.
850@end defopt 848@end defopt
851 849
850@defopt lisp-eval-depth-reserve
851In order to be able to debug infinite recursion errors, when invoking the
852Lisp debugger, Emacs increases temporarily the value of
853@code{max-lisp-eval-depth}, if there is little room left, to make sure
854the debugger itself has room to execute. The same happens when
855running the handler of a @code{handler-bind}. @xref{Handling Errors}.
856
857The variable @code{lisp-eval-depth-reserve} bounds the extra depth
858that Emacs can add to @code{max-lisp-eval-depth} for those
859exceptional circumstances.
860
861The default value of this variable is 200.
862@end defopt
863
864
852@defvar values 865@defvar values
853The value of this variable is a list of the values returned by all the 866The value of this variable is a list of the values returned by all the
854expressions that were read, evaluated, and printed from buffers 867expressions that were read, evaluated, and printed from buffers
diff --git a/etc/NEWS b/etc/NEWS
index db3b838c380..7bbfbf9512d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1396,6 +1396,11 @@ is already loaded, in which case it either signals an error or
1396forcibly reloads the file that defines the feature. 1396forcibly reloads the file that defines the feature.
1397 1397
1398+++ 1398+++
1399** New variable 'lisp-eval-depth-reserve'.
1400It puts a limit to the amount by which Emacs can temporarily increase
1401'max-lisp-eval-depth' when handling signals.
1402
1403+++
1399** New special form 'handler-bind'. 1404** New special form 'handler-bind'.
1400Provides a functionality similar to `condition-case` except it runs the 1405Provides a functionality similar to `condition-case` except it runs the
1401handler code without unwinding the stack, such that we can record the 1406handler code without unwinding the stack, such that we can record the
diff --git a/src/eval.c b/src/eval.c
index 7e578a1aa05..b982c124184 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -212,7 +212,6 @@ void
212init_eval_once (void) 212init_eval_once (void)
213{ 213{
214 /* Don't forget to update docs (lispref node "Eval"). */ 214 /* Don't forget to update docs (lispref node "Eval"). */
215 max_lisp_eval_depth = 1600;
216 Vrun_hooks = Qnil; 215 Vrun_hooks = Qnil;
217 pdumper_do_now_and_after_load (init_eval_once_for_pdumper); 216 pdumper_do_now_and_after_load (init_eval_once_for_pdumper);
218} 217}
@@ -248,22 +247,29 @@ init_eval (void)
248 redisplay_deep_handler = NULL; 247 redisplay_deep_handler = NULL;
249} 248}
250 249
251/* Ensure that *M is at least A + B if possible, or is its maximum
252 value otherwise. */
253
254static void 250static void
255max_ensure_room (intmax_t *m, intmax_t a, intmax_t b) 251restore_stack_limits (Lisp_Object data)
256{ 252{
257 intmax_t sum = ckd_add (&sum, a, b) ? INTMAX_MAX : sum; 253 intmax_t old_depth;
258 *m = max (*m, sum); 254 integer_to_intmax (data, &old_depth);
255 lisp_eval_depth_reserve += max_lisp_eval_depth - old_depth;
256 max_lisp_eval_depth = old_depth;
259} 257}
260 258
261/* Unwind-protect function used by call_debugger. */ 259/* Try and ensure that we have at least B dpeth available. */
262 260
263static void 261static void
264restore_stack_limits (Lisp_Object data) 262max_ensure_room (intmax_t b)
265{ 263{
266 integer_to_intmax (data, &max_lisp_eval_depth); 264 intmax_t sum = ckd_add (&sum, lisp_eval_depth, b) ? INTMAX_MAX : sum;
265 intmax_t diff = min (sum - max_lisp_eval_depth, lisp_eval_depth_reserve);
266 if (diff <= 0)
267 return;
268 intmax_t old_depth = max_lisp_eval_depth;
269 max_lisp_eval_depth += diff;
270 lisp_eval_depth_reserve -= diff;
271 /* Restore limits after leaving the debugger. */
272 record_unwind_protect (restore_stack_limits, make_int (old_depth));
267} 273}
268 274
269/* Call the Lisp debugger, giving it argument ARG. */ 275/* Call the Lisp debugger, giving it argument ARG. */
@@ -274,16 +280,12 @@ call_debugger (Lisp_Object arg)
274 bool debug_while_redisplaying; 280 bool debug_while_redisplaying;
275 specpdl_ref count = SPECPDL_INDEX (); 281 specpdl_ref count = SPECPDL_INDEX ();
276 Lisp_Object val; 282 Lisp_Object val;
277 intmax_t old_depth = max_lisp_eval_depth;
278 283
279 /* The previous value of 40 is too small now that the debugger 284 /* The previous value of 40 is too small now that the debugger
280 prints using cl-prin1 instead of prin1. Printing lists nested 8 285 prints using cl-prin1 instead of prin1. Printing lists nested 8
281 deep (which is the value of print-level used in the debugger) 286 deep (which is the value of print-level used in the debugger)
282 currently requires 77 additional frames. See bug#31919. */ 287 currently requires 77 additional frames. See bug#31919. */
283 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100); 288 max_ensure_room (100);
284
285 /* Restore limits after leaving the debugger. */
286 record_unwind_protect (restore_stack_limits, make_int (old_depth));
287 289
288#ifdef HAVE_WINDOW_SYSTEM 290#ifdef HAVE_WINDOW_SYSTEM
289 if (display_hourglass_p) 291 if (display_hourglass_p)
@@ -1802,16 +1804,13 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1802 1804
1803 /* This hook is used by edebug. */ 1805 /* This hook is used by edebug. */
1804 if (! NILP (Vsignal_hook_function) 1806 if (! NILP (Vsignal_hook_function)
1805 && ! NILP (error_symbol) 1807 && ! NILP (error_symbol))
1806 /* Don't try to call a lisp function if we've already overflowed
1807 the specpdl stack. */
1808 && specpdl_ptr < specpdl_end)
1809 { 1808 {
1810 /* Edebug takes care of restoring these variables when it exits. */ 1809 specpdl_ref count = SPECPDL_INDEX ();
1811 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20); 1810 max_ensure_room (20);
1812
1813 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */ 1811 /* FIXME: 'handler-bind' makes `signal-hook-function' obsolete? */
1814 call2 (Vsignal_hook_function, error_symbol, data); 1812 call2 (Vsignal_hook_function, error_symbol, data);
1813 unbind_to (count, Qnil);
1815 } 1814 }
1816 1815
1817 conditions = Fget (real_error_symbol, Qerror_conditions); 1816 conditions = Fget (real_error_symbol, Qerror_conditions);
@@ -1849,9 +1848,12 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1849 Lisp_Object error_data 1848 Lisp_Object error_data
1850 = (NILP (error_symbol) 1849 = (NILP (error_symbol)
1851 ? data : Fcons (error_symbol, data)); 1850 ? data : Fcons (error_symbol, data));
1851 specpdl_ref count = SPECPDL_INDEX ();
1852 max_ensure_room (20);
1852 push_handler (make_fixnum (skip + h->bytecode_dest), 1853 push_handler (make_fixnum (skip + h->bytecode_dest),
1853 SKIP_CONDITIONS); 1854 SKIP_CONDITIONS);
1854 call1 (h->val, error_data); 1855 call1 (h->val, error_data);
1856 unbind_to (count, Qnil);
1855 pop_handler (); 1857 pop_handler ();
1856 } 1858 }
1857 continue; 1859 continue;
@@ -1901,8 +1903,8 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
1901 && NILP (Vinhibit_debugger) 1903 && NILP (Vinhibit_debugger)
1902 && !NILP (Ffboundp (Qdebug_early))) 1904 && !NILP (Ffboundp (Qdebug_early)))
1903 { 1905 {
1904 max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
1905 specpdl_ref count = SPECPDL_INDEX (); 1906 specpdl_ref count = SPECPDL_INDEX ();
1907 max_ensure_room (100);
1906 AUTO_STRING (redisplay_trace, "*Redisplay-trace*"); 1908 AUTO_STRING (redisplay_trace, "*Redisplay-trace*");
1907 Lisp_Object redisplay_trace_buffer; 1909 Lisp_Object redisplay_trace_buffer;
1908 AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* */ 1910 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.
4345You can safely make it considerably larger than its default value, 4347You can safely make it considerably larger than its default value,
4346if that proves inconveniently small. However, if you increase it too far, 4348if that proves inconveniently small. However, if you increase it too far,
4347Emacs could overflow the real C stack, and crash. */); 4349Emacs could overflow the real C stack, and crash. */);
4350 max_lisp_eval_depth = 1600;
4351
4352 DEFVAR_INT ("lisp-eval-depth-reserve", lisp_eval_depth_reserve,
4353 doc: /* Extra depth that can be allocated to handle errors.
4354This is the max depth that the system will add to `max-lisp-eval-depth'
4355when calling debuggers or `handler-bind' handlers. */);
4356 lisp_eval_depth_reserve = 200;
4348 4357
4349 DEFVAR_LISP ("quit-flag", Vquit_flag, 4358 DEFVAR_LISP ("quit-flag", Vquit_flag,
4350 doc: /* Non-nil causes `eval' to abort, unless `inhibit-quit' is non-nil. 4359 doc: /* Non-nil causes `eval' to abort, unless `inhibit-quit' is non-nil.