diff options
| author | Stefan Monnier | 2023-12-26 23:56:09 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2024-01-04 16:36:22 -0500 |
| commit | 02edbc88a1210b8d5a3e62ca4f03ffd17b23cbf7 (patch) | |
| tree | a37f8100646efe24a7224c947c7bc66ec4683c16 | |
| parent | a5dcc1abea32abc906abfb66599c280b01d6ba27 (diff) | |
| download | emacs-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.texi | 19 | ||||
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | src/eval.c | 55 |
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 | ||
| 845 | The default value of this variable is 1600. If you set it to a value | 845 | The default value of this variable is 1600. If you set it to a value |
| 846 | less than 100, Lisp will reset it to 100 if the given value is | 846 | less than 100, Lisp will reset it to 100 if the given value is |
| 847 | reached. Entry to the Lisp debugger increases the value, if there is | 847 | reached. |
| 848 | little room left, to make sure the debugger itself has room to | ||
| 849 | execute. | ||
| 850 | @end defopt | 848 | @end defopt |
| 851 | 849 | ||
| 850 | @defopt lisp-eval-depth-reserve | ||
| 851 | In order to be able to debug infinite recursion errors, when invoking the | ||
| 852 | Lisp debugger, Emacs increases temporarily the value of | ||
| 853 | @code{max-lisp-eval-depth}, if there is little room left, to make sure | ||
| 854 | the debugger itself has room to execute. The same happens when | ||
| 855 | running the handler of a @code{handler-bind}. @xref{Handling Errors}. | ||
| 856 | |||
| 857 | The variable @code{lisp-eval-depth-reserve} bounds the extra depth | ||
| 858 | that Emacs can add to @code{max-lisp-eval-depth} for those | ||
| 859 | exceptional circumstances. | ||
| 860 | |||
| 861 | The default value of this variable is 200. | ||
| 862 | @end defopt | ||
| 863 | |||
| 864 | |||
| 852 | @defvar values | 865 | @defvar values |
| 853 | The value of this variable is a list of the values returned by all the | 866 | The value of this variable is a list of the values returned by all the |
| 854 | expressions that were read, evaluated, and printed from buffers | 867 | expressions that were read, evaluated, and printed from buffers |
| @@ -1396,6 +1396,11 @@ is already loaded, in which case it either signals an error or | |||
| 1396 | forcibly reloads the file that defines the feature. | 1396 | forcibly reloads the file that defines the feature. |
| 1397 | 1397 | ||
| 1398 | +++ | 1398 | +++ |
| 1399 | ** New variable 'lisp-eval-depth-reserve'. | ||
| 1400 | It 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'. |
| 1400 | Provides a functionality similar to `condition-case` except it runs the | 1405 | Provides a functionality similar to `condition-case` except it runs the |
| 1401 | handler code without unwinding the stack, such that we can record the | 1406 | handler 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 | |||
| 212 | init_eval_once (void) | 212 | init_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 | |||
| 254 | static void | 250 | static void |
| 255 | max_ensure_room (intmax_t *m, intmax_t a, intmax_t b) | 251 | restore_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 | ||
| 263 | static void | 261 | static void |
| 264 | restore_stack_limits (Lisp_Object data) | 262 | max_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. | |||
| 4345 | You can safely make it considerably larger than its default value, | 4347 | You can safely make it considerably larger than its default value, |
| 4346 | if that proves inconveniently small. However, if you increase it too far, | 4348 | if that proves inconveniently small. However, if you increase it too far, |
| 4347 | Emacs could overflow the real C stack, and crash. */); | 4349 | Emacs 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. | ||
| 4354 | This is the max depth that the system will add to `max-lisp-eval-depth' | ||
| 4355 | when 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. |