* bug#57911: Abolish max-specpdl-size
2022-09-19 7:10 ` Lars Ingebrigtsen
@ 2022-09-19 9:35 ` Mattias Engdegård
2022-09-19 12:27 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2022-09-19 12:40 ` Lars Ingebrigtsen
0 siblings, 2 replies; 25+ messages in thread
From: Mattias Engdegård @ 2022-09-19 9:35 UTC (permalink / raw)
To: Lars Ingebrigtsen; +Cc: 57911, Stefan Monnier
[-- Attachment #1: Type: text/plain, Size: 233 bytes --]
19 sep. 2022 kl. 09.10 skrev Lars Ingebrigtsen <larsi@gnus.org>:
> I think that sounds like it could be very helpful -- having two
> variables that do kinda similar limits here is very confusing.
On we go then, here is the patch.
[-- Attachment #2: 0001-Abolish-max-specpdl-size-bug-57911.patch --]
[-- Type: application/octet-stream, Size: 32227 bytes --]
From 997dbb1284c882730f0a515f49a93babf3fcdcee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= <mattiase@acm.org>
Date: Mon, 19 Sep 2022 10:55:09 +0200
Subject: [PATCH] Abolish max-specpdl-size (bug#57911)
The max-lisp-eval-depth limit is sufficient to prevent unbounded stack
growth including the specbind stack; simplify matters for the user by
not having them to worry about two different limits. This change
turns max-specpdl-size into a harmless variable with no effects,
to keep existing code happy.
* lisp/subr.el (max-specpdl-size): Define as an ordinary dynamic variable.
* admin/grammars/Makefile.in:
* doc/lispintro/emacs-lisp-intro.texi (Loops & Recursion):
* doc/lispref/control.texi (Cleanups):
* doc/lispref/edebug.texi (Checking Whether to Stop):
* doc/lispref/eval.texi (Eval):
* doc/lispref/variables.texi (Local Variables):
* doc/misc/calc.texi (Recursion Depth):
Update documentation.
* etc/NEWS: Announce.
* src/eval.c
(FletX): Use safe iteration to guard against circular bindings list.
(syms_of_eval): Remove old max-specpdl-size definition.
(init_eval_once, restore_stack_limits, call_debugger)
(signal_or_quit, grow_specpdl_allocation):
* leim/Makefile.in:
* lisp/Makefile.in:
* lisp/calc/calc-stuff.el (calc-more-recursion-depth)
(calc-less-recursion-depth):
* lisp/calc/calc.el (calc-do):
* lisp/cedet/semantic/ede-grammar.el (ede-proj-makefile-insert-rules):
* lisp/cedet/semantic/grammar.el (semantic-grammar-batch-build-one-package):
* lisp/cus-start.el (standard):
* lisp/emacs-lisp/comp.el (comp--native-compile):
* lisp/emacs-lisp/edebug.el (edebug-max-depth):
(edebug-read-and-maybe-wrap-form, edebug-default-enter):
* lisp/emacs-lisp/regexp-opt.el (regexp-opt):
* lisp/eshell/esh-mode.el (eshell-mode):
* lisp/loadup.el (max-specpdl-size):
* lisp/mh-e/mh-e.el (mh-invisible-headers):
* lisp/net/shr.el (shr-insert-document, shr-descend):
* lisp/play/hanoi.el (hanoi-internal):
* lisp/progmodes/cperl-mode.el:
* src/fileio.c (Fdo_auto_save):
Remove references to and modifications of max-specpdl-size.
---
admin/grammars/Makefile.in | 2 +-
doc/lispintro/emacs-lisp-intro.texi | 5 +--
doc/lispref/control.texi | 5 ---
doc/lispref/edebug.texi | 5 +--
doc/lispref/eval.texi | 5 +--
doc/lispref/variables.texi | 21 ----------
doc/misc/calc.texi | 4 --
etc/NEWS | 6 +++
leim/Makefile.in | 2 -
lisp/Makefile.in | 8 ++--
lisp/calc/calc-stuff.el | 8 +---
lisp/calc/calc.el | 3 +-
lisp/cedet/semantic/ede-grammar.el | 7 ++--
lisp/cedet/semantic/grammar.el | 1 -
lisp/cus-start.el | 1 -
lisp/emacs-lisp/comp.el | 1 -
lisp/emacs-lisp/edebug.el | 6 +--
lisp/emacs-lisp/regexp-opt.el | 1 -
lisp/eshell/esh-mode.el | 1 -
lisp/loadup.el | 4 +-
lisp/mh-e/mh-e.el | 4 +-
lisp/net/shr.el | 62 +++++++++++++----------------
lisp/play/hanoi.el | 5 +--
lisp/progmodes/cperl-mode.el | 1 -
lisp/subr.el | 7 ++++
src/eval.c | 60 +++-------------------------
src/fileio.c | 5 ---
27 files changed, 67 insertions(+), 173 deletions(-)
diff --git a/admin/grammars/Makefile.in b/admin/grammars/Makefile.in
index 4ca88982cd..178c79b7a0 100644
--- a/admin/grammars/Makefile.in
+++ b/admin/grammars/Makefile.in
@@ -35,7 +35,7 @@ top_builddir =
EMACS = ${top_builddir}/src/emacs
emacs = "${EMACS}" -batch --no-site-file --no-site-lisp \
- --eval '(setq max-specpdl-size 5000)' --eval '(setq load-prefer-newer t)'
+ --eval '(setq load-prefer-newer t)'
make_bovine = ${emacs} -l semantic/bovine/grammar -f bovine-batch-make-parser
make_wisent = ${emacs} -l semantic/wisent/grammar -f wisent-batch-make-parser
diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi
index 47a5a870fd..df8fa2f8e7 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -10100,9 +10100,8 @@ Loops & Recursion
frugal of mental resources---sometimes use considerable computer
resources. Emacs was designed to run on machines that we now consider
limited and its default settings are conservative. You may want to
-increase the values of @code{max-specpdl-size} and
-@code{max-lisp-eval-depth}. In my @file{.emacs} file, I set them to
-15 and 30 times their default value.}.
+increase the value of @code{max-lisp-eval-depth}. In my @file{.emacs}
+file, I set it to 30 times its default value.}.
@menu
* while:: Causing a stretch of code to repeat.
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index d4520ebdee..ee2acdb002 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -2366,11 +2366,6 @@ Cleanups
guaranteed to evaluate the rest of them. If the failure of one of the
@var{cleanup-forms} has the potential to cause trouble, then protect
it with another @code{unwind-protect} around that form.
-
-The number of currently active @code{unwind-protect} forms counts,
-together with the number of local variable bindings, against the limit
-@code{max-specpdl-size} (@pxref{Definition of max-specpdl-size,, Local
-Variables}).
@end defspec
For example, here we make an invisible buffer for temporary use, and
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index 56f7b7bdfa..6a51489d8a 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1032,9 +1032,8 @@ Checking Whether to Stop
@itemize @bullet
@item
@vindex edebug-max-depth
-@code{max-lisp-eval-depth} (@pxref{Eval}) and @code{max-specpdl-size}
-(@pxref{Local Variables}) are both increased to reduce Edebug's impact
-on the stack. You could, however, still run out of stack space when
+@code{max-lisp-eval-depth} (@pxref{Eval}) is increased to reduce Edebug's
+impact on the stack. You could, however, still run out of stack space when
using Edebug. You can also enlarge the value of
@code{edebug-max-depth} if Edebug reaches the limit of recursion depth
instrumenting code that contains very large quoted lists.
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index 6e29a5403f..11c321b32e 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -830,7 +830,7 @@ Eval
@code{apply}, and @code{funcall} before an error is signaled (with error
message @code{"Lisp nesting exceeds max-lisp-eval-depth"}).
-This limit, with the associated error when it is exceeded, is one way
+This limit, with the associated error when it is exceeded, is how
Emacs Lisp avoids infinite recursion on an ill-defined function. If
you increase the value of @code{max-lisp-eval-depth} too much, such
code can cause stack overflow instead. On some systems, this overflow
@@ -851,9 +851,6 @@ Eval
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.
-
-@code{max-specpdl-size} provides another limit on nesting.
-@xref{Definition of max-specpdl-size,, Local Variables}.
@end defopt
@defvar values
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 975e945b34..ccd19630bf 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -358,27 +358,6 @@ Local Variables
like ordinary local bindings, but they are localized depending on
where you are in Emacs.
-@defopt max-specpdl-size
-@anchor{Definition of max-specpdl-size}
-@cindex variable limit error
-@cindex evaluation error
-@cindex infinite recursion
-This variable defines the limit on the total number of local variable
-bindings and @code{unwind-protect} cleanups (@pxref{Cleanups,,
-Cleaning Up from Nonlocal Exits}) that are allowed before Emacs
-signals an error (with data @code{"Variable binding depth exceeds
-max-specpdl-size"}).
-
-This limit, with the associated error when it is exceeded, is one way
-that Lisp avoids infinite recursion on an ill-defined function.
-@code{max-lisp-eval-depth} provides another limit on depth of nesting.
-@xref{Definition of max-lisp-eval-depth,, Eval}.
-
-The default value is 2500. Entry to the Lisp debugger increases the
-value, if there is little room left, to make sure the debugger itself
-has room to execute.
-@end defopt
-
@node Void Variables
@section When a Variable is Void
@cindex @code{void-variable} error
diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi
index 98f59b89c0..89a340e734 100644
--- a/doc/misc/calc.texi
+++ b/doc/misc/calc.texi
@@ -10392,7 +10392,6 @@ Recursion Depth
@cindex Recursion depth
@cindex ``Computation got stuck'' message
@cindex @code{max-lisp-eval-depth}
-@cindex @code{max-specpdl-size}
Calc uses recursion in many of its calculations. Emacs Lisp keeps a
variable @code{max-lisp-eval-depth} which limits the amount of recursion
possible in an attempt to recover from program bugs. If a calculation
@@ -10406,9 +10405,6 @@ Recursion Depth
decreases this limit by a factor of two, down to a minimum value of 200.
The default value is 1000.
-These commands also double or halve @code{max-specpdl-size}, another
-internal Lisp recursion limit. The minimum value for this limit is 600.
-
@node Caches
@subsection Caches
diff --git a/etc/NEWS b/etc/NEWS
index a739d74b65..63ceb7ba34 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3806,6 +3806,12 @@ the same but works by modifying LIST destructively.
---
** 'string-split' is now an alias for 'split-string'.
++++
+** 'max-specpdl-size' is no longer used.
+Now 'max-lisp-eval-depth' alone is used for limiting Lisp recursion
+and stack usage. 'max-specpdl-size' is still present as a plain
+variable for compatibility but its limiting powers have been taken away.
+
\f
* Changes in Emacs 29.1 on Non-Free Operating Systems
diff --git a/leim/Makefile.in b/leim/Makefile.in
index 29b9f3b2f8..fbd733b7f6 100644
--- a/leim/Makefile.in
+++ b/leim/Makefile.in
@@ -128,7 +128,6 @@ leim-list.el:
${leimdir}/leim-list.el: ${srcdir}/leim-ext.el ${TIT_MISC}
$(AM_V_GEN)rm -f $@
$(AM_V_at)${RUN_EMACS} -l international/quail \
- --eval "(setq max-specpdl-size 5000)" \
--eval "(update-leim-list-file (unmsys--file-name \"${leimdir}\"))"
$(AM_V_at)sed -n -e '/^[^;]/p' -e 's/^;\(;*\)inc /;\1 /p' < $< >> $@
@@ -139,7 +138,6 @@ .PHONY:
generate-ja-dic: ${leimdir}/ja-dic/ja-dic.el
${leimdir}/ja-dic/ja-dic.el: $(srcdir)/SKK-DIC/SKK-JISYO.L
$(AM_V_GEN)$(RUN_EMACS) -batch -l ja-dic-cnv \
- --eval "(setq max-specpdl-size 5000)" \
-f batch-skkdic-convert -dir "$(leimdir)/ja-dic" $(JA_DIC_NO_REDUCTION_OPTION) "$<"
${srcdir}/../lisp/language/pinyin.el: ${srcdir}/MISC-DIC/pinyin.map
diff --git a/lisp/Makefile.in b/lisp/Makefile.in
index c73a623cce..bcf4a3146d 100644
--- a/lisp/Makefile.in
+++ b/lisp/Makefile.in
@@ -70,9 +70,7 @@ BYTE_COMPILE_FLAGS =
--eval "(setq load-prefer-newer t byte-compile-warnings 'all)" \
$(BYTE_COMPILE_EXTRA_FLAGS)
# ... but we must prefer .elc files for those in the early bootstrap.
-# A larger `max-specpdl-size' is needed for emacs-lisp/comp.el.
-compile-first: BYTE_COMPILE_FLAGS = \
- --eval '(setq max-specpdl-size 5000)' $(BYTE_COMPILE_EXTRA_FLAGS)
+compile-first: BYTE_COMPILE_FLAGS = $(BYTE_COMPILE_EXTRA_FLAGS)
# Files to compile before others during a bootstrap. This is done to
# speed up the bootstrap process. They're ordered by size, so we use
@@ -342,8 +340,8 @@ compile-first:
.PHONY: compile-targets
# TARGETS is set dynamically in the recursive call from 'compile-main'.
-# Do not build comp.el unless necessary not to exceed max-specpdl-size and
-# max-lisp-eval-depth in normal builds.
+# Do not build comp.el unless necessary not to exceed max-lisp-eval-depth
+# in normal builds.
ifneq ($(HAVE_NATIVE_COMP),yes)
compile-targets: $(filter-out ./emacs-lisp/comp-cstr.elc,$(filter-out ./emacs-lisp/comp.elc,$(TARGETS)))
else
diff --git a/lisp/calc/calc-stuff.el b/lisp/calc/calc-stuff.el
index 0e8ea42bed..758b920184 100644
--- a/lisp/calc/calc-stuff.el
+++ b/lisp/calc/calc-stuff.el
@@ -52,18 +52,14 @@ calc-more-recursion-depth
(calc-less-recursion-depth n)
(let ((n (if n (prefix-numeric-value n) 2)))
(if (> n 1)
- (setq max-specpdl-size (* max-specpdl-size n)
- max-lisp-eval-depth (* max-lisp-eval-depth n))))
+ (setq max-lisp-eval-depth (* max-lisp-eval-depth n))))
(message "max-lisp-eval-depth is now %d" max-lisp-eval-depth))))
(defun calc-less-recursion-depth (n)
(interactive "P")
(let ((n (if n (prefix-numeric-value n) 2)))
(if (> n 1)
- (setq max-specpdl-size
- (max (/ max-specpdl-size n) 600)
- max-lisp-eval-depth
- (max (/ max-lisp-eval-depth n) 200))))
+ (setq max-lisp-eval-depth (max (/ max-lisp-eval-depth n) 200))))
(message "max-lisp-eval-depth is now %d" max-lisp-eval-depth))
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index 5077c8c852..c0f87ad3d4 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -1625,8 +1625,7 @@ calc-do
(error
(if (and (eq (car err) 'error)
(stringp (nth 1 err))
- (string-match "max-specpdl-size\\|max-lisp-eval-depth"
- (nth 1 err)))
+ (string-search "max-lisp-eval-depth" (nth 1 err)))
(error (substitute-command-keys
"Computation got stuck or ran too long. Type \\`M' to increase the limit"))
(setq calc-aborted-prefix nil)
diff --git a/lisp/cedet/semantic/ede-grammar.el b/lisp/cedet/semantic/ede-grammar.el
index ff9f991ff4..40ff8fc86d 100644
--- a/lisp/cedet/semantic/ede-grammar.el
+++ b/lisp/cedet/semantic/ede-grammar.el
@@ -177,10 +177,9 @@ ede-proj-makefile-insert-variables
(cl-defmethod ede-proj-makefile-insert-rules :after ((this semantic-ede-proj-target-grammar))
"Insert rules needed by THIS target.
-This raises `max-specpdl-size' and `max-lisp-eval-depth', which can be
-needed for the compilation of the resulting parsers."
- (insert (format "%s: EMACSFLAGS+= --eval '(setq max-specpdl-size 1500 \
-max-lisp-eval-depth 700)'\n"
+This raises `max-lisp-eval-depth', which can be needed for the compilation
+of the resulting parsers."
+ (insert (format "%s: EMACSFLAGS+= --eval '(setq max-lisp-eval-depth 700)'\n"
(oref this name))))
(cl-defmethod ede-proj-makefile-insert-dist-dependencies ((this semantic-ede-proj-target-grammar))
diff --git a/lisp/cedet/semantic/grammar.el b/lisp/cedet/semantic/grammar.el
index 72037f4710..8ba0e346ff 100644
--- a/lisp/cedet/semantic/grammar.el
+++ b/lisp/cedet/semantic/grammar.el
@@ -1009,7 +1009,6 @@ semantic-grammar-batch-build-one-package
packagename (byte-compile-dest-file packagename))
(let (;; Some complex grammar table expressions need a few
;; more resources than the default.
- (max-specpdl-size (max 3000 max-specpdl-size))
(max-lisp-eval-depth (max 1000 max-lisp-eval-depth))
)
;; byte compile the resultant file
diff --git a/lisp/cus-start.el b/lisp/cus-start.el
index 0e1cb4589d..d7fb56c985 100644
--- a/lisp/cus-start.el
+++ b/lisp/cus-start.el
@@ -251,7 +251,6 @@ minibuffer-prompt-properties--setter
;; emacs.c
(report-emacs-bug-address emacsbug string)
;; eval.c
- (max-specpdl-size limits integer)
(max-lisp-eval-depth limits integer)
(max-mini-window-height limits
(choice (const :tag "quarter screen" nil)
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index a9087313b1..35acbff9b1 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4044,7 +4044,6 @@ comp--native-compile
(list "Not a function symbol or file" function-or-file)))
(catch 'no-native-compile
(let* ((print-symbols-bare t)
- (max-specpdl-size (max max-specpdl-size 5000))
(data function-or-file)
(comp-native-compiling t)
(byte-native-qualities nil)
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 31c05057bf..67704bdb51 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -129,7 +129,7 @@ edebug-max-depth
containing very large quoted lists, it may reach this limit and give
the error message \"Too deep - perhaps infinite loop in spec?\".
Make this limit larger to countermand that, but you may also need to
-increase `max-lisp-eval-depth' and `max-specpdl-size'."
+increase `max-lisp-eval-depth'."
:type 'integer
:version "26.1")
@@ -1107,8 +1107,7 @@ edebug-read-and-maybe-wrap-form
edebug-best-error
edebug-error-point
;; Do this once here instead of several times.
- (max-lisp-eval-depth (+ 800 max-lisp-eval-depth))
- (max-specpdl-size (+ 2000 max-specpdl-size)))
+ (max-lisp-eval-depth (+ 800 max-lisp-eval-depth)))
(let ((no-match
(catch 'no-match
(setq result (edebug-read-and-maybe-wrap-form1))
@@ -2317,7 +2316,6 @@ edebug-default-enter
;; but not inside an unwind-protect.
;; Doing it here also keeps it from growing too large.
(max-lisp-eval-depth (+ 100 max-lisp-eval-depth)) ; too much??
- (max-specpdl-size (+ 200 max-specpdl-size))
(debugger edebug-debugger) ; only while edebug is active.
(edebug-outside-debug-on-error debug-on-error)
diff --git a/lisp/emacs-lisp/regexp-opt.el b/lisp/emacs-lisp/regexp-opt.el
index cae5dd00d1..4d5a39458d 100644
--- a/lisp/emacs-lisp/regexp-opt.el
+++ b/lisp/emacs-lisp/regexp-opt.el
@@ -133,7 +133,6 @@ regexp-opt
(save-match-data
;; Recurse on the sorted list.
(let* ((max-lisp-eval-depth 10000)
- (max-specpdl-size 10000)
(completion-ignore-case nil)
(completion-regexp-list nil)
(open (cond ((stringp paren) paren) (paren "\\(")))
diff --git a/lisp/eshell/esh-mode.el b/lisp/eshell/esh-mode.el
index 69069183a3..8f11e6f04a 100644
--- a/lisp/eshell/esh-mode.el
+++ b/lisp/eshell/esh-mode.el
@@ -331,7 +331,6 @@ eshell-mode
(setq-local require-final-newline nil)
(setq-local max-lisp-eval-depth (max 3000 max-lisp-eval-depth))
- (setq-local max-specpdl-size (max 6000 max-lisp-eval-depth))
(setq-local eshell-last-input-start (point-marker))
(setq-local eshell-last-input-end (point-marker))
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 634a331436..c01c827a75 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -244,9 +244,7 @@
(load "language/indonesian")
(load "indent")
-(let ((max-specpdl-size (max max-specpdl-size 1800)))
- ;; A particularly demanding file to load; 1600 does not seem to be enough.
- (load "emacs-lisp/cl-generic"))
+(load "emacs-lisp/cl-generic")
(load "simple")
(load "emacs-lisp/seq")
(load "emacs-lisp/nadvice")
diff --git a/lisp/mh-e/mh-e.el b/lisp/mh-e/mh-e.el
index 0ad934107d..9a04d89097 100644
--- a/lisp/mh-e/mh-e.el
+++ b/lisp/mh-e/mh-e.el
@@ -2831,9 +2831,7 @@ mh-invisible-headers
(setq mh-invisible-header-fields-compiled
(concat
"^"
- ;; workaround for insufficient default
- (let ((max-specpdl-size 1000))
- (regexp-opt fields t))))
+ (regexp-opt fields t)))
(setq mh-invisible-header-fields-compiled nil))))
;; Compile invisible header fields.
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 54ce9b1a41..d56420eb02 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -373,7 +373,6 @@ shr-insert-document
shr-width
(* shr-width (frame-char-width)))
(shr--window-width)))
- (max-specpdl-size max-specpdl-size)
(shr--link-targets nil)
(hscroll (window-hscroll))
;; `bidi-display-reordering' is supposed to be only used for
@@ -625,41 +624,34 @@ shr-descend
(shr-stylesheet shr-stylesheet)
(shr-depth (1+ shr-depth))
(start (point)))
- ;; shr uses many frames per nested node.
- (if (and (> shr-depth (/ max-specpdl-size 15))
- (not (and shr-offer-extend-specpdl
- (y-or-n-p "Too deeply nested to render properly; increase `max-specpdl-size'?")
- (setq max-specpdl-size (* max-specpdl-size 2)))))
- (setq shr-warning
- "Not rendering the complete page because of too-deep nesting")
+ (when style
+ (if (string-match-p "color\\|display\\|border-collapse" style)
+ (setq shr-stylesheet (nconc (shr-parse-style style)
+ shr-stylesheet))
+ (setq style nil)))
+ ;; If we have a display:none, then just ignore this part of the DOM.
+ (unless (or (equal (cdr (assq 'display shr-stylesheet)) "none")
+ (and shr-discard-aria-hidden
+ (equal (dom-attr dom 'aria-hidden) "true")))
+ ;; We don't use shr-indirect-call here, since shr-descend is
+ ;; the central bit of shr.el, and should be as fast as
+ ;; possible. Having one more level of indirection with its
+ ;; negative effect on performance is deemed unjustified in
+ ;; this case.
+ (cond (external
+ (funcall external dom))
+ ((fboundp function)
+ (funcall function dom))
+ (t
+ (shr-generic dom)))
+ (when-let ((id (dom-attr dom 'id)))
+ (push (cons id (set-marker (make-marker) start)) shr--link-targets))
+ ;; If style is set, then this node has set the color.
(when style
- (if (string-match-p "color\\|display\\|border-collapse" style)
- (setq shr-stylesheet (nconc (shr-parse-style style)
- shr-stylesheet))
- (setq style nil)))
- ;; If we have a display:none, then just ignore this part of the DOM.
- (unless (or (equal (cdr (assq 'display shr-stylesheet)) "none")
- (and shr-discard-aria-hidden
- (equal (dom-attr dom 'aria-hidden) "true")))
- ;; We don't use shr-indirect-call here, since shr-descend is
- ;; the central bit of shr.el, and should be as fast as
- ;; possible. Having one more level of indirection with its
- ;; negative effect on performance is deemed unjustified in
- ;; this case.
- (cond (external
- (funcall external dom))
- ((fboundp function)
- (funcall function dom))
- (t
- (shr-generic dom)))
- (when-let ((id (dom-attr dom 'id)))
- (push (cons id (set-marker (make-marker) start)) shr--link-targets))
- ;; If style is set, then this node has set the color.
- (when style
- (shr-colorize-region
- start (point)
- (cdr (assq 'color shr-stylesheet))
- (cdr (assq 'background-color shr-stylesheet))))))))
+ (shr-colorize-region
+ start (point)
+ (cdr (assq 'color shr-stylesheet))
+ (cdr (assq 'background-color shr-stylesheet)))))))
(defun shr-fill-text (text)
(if (zerop (length text))
diff --git a/lisp/play/hanoi.el b/lisp/play/hanoi.el
index 58fb82b6ed..1a4b6dbeb1 100644
--- a/lisp/play/hanoi.el
+++ b/lisp/play/hanoi.el
@@ -149,10 +149,9 @@ hanoi-internal
(setq show-trailing-whitespace nil)
(unwind-protect
(let*
- (;; These lines can cause Emacs to crash if you ask for too
- ;; many rings. If you uncomment them, on most systems you
+ (;; This line can cause Emacs to crash if you ask for too
+ ;; many rings. If you uncomment it, on most systems you
;; can get 10,000+ rings.
- ;;(max-specpdl-size (max max-specpdl-size (* nrings 15)))
;;(max-lisp-eval-depth (max max-lisp-eval-depth (+ nrings 20)))
(vert (not hanoi-horizontal-flag))
(pole-width (length (format "%d" (max 0 (1- nrings)))))
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index 614ee60fa0..c3704a05db 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -3718,7 +3718,6 @@ cperl-process-here-doc
overshoot
warning-message)))
-;; Debugging this may require (setq max-specpdl-size 2000)...
(defun cperl-find-pods-heres (&optional min max non-inter end ignore-max end-of-here-doc)
"Scan the buffer for hard-to-parse Perl constructions.
If `cperl-pod-here-fontify' is non-nil after evaluation,
diff --git a/lisp/subr.el b/lisp/subr.el
index d7cdc28abb..0e8cb2fcd6 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -376,6 +376,13 @@ ignore-error
\f
;;;; Basic Lisp functions.
+(defvar max-specpdl-size 2500
+ "Former limit on specbindings, now without effect.
+This variable used to limit the size of the specpdl stack which,
+among other things, held dynamic variable bindings and `unwind-protect'
+activations. To prevent runaway recursion, use `max-lisp-eval-lisp-depth'
+instead; it will indirectly limit the specpdl stack size as well.")
+
(defvar gensym-counter 0
"Number used to construct the name of the next symbol created by `gensym'.")
diff --git a/src/eval.c b/src/eval.c
index bd414fb868..7da1d8fb98 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -211,9 +211,7 @@ backtrace_thread_next (struct thread_state *tstate, union specbinding *pdl)
void
init_eval_once (void)
{
- /* Don't forget to update docs
- (lispref nodes "Local Variables" and "Eval"). */
- max_specpdl_size = 2500;
+ /* 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);
@@ -265,8 +263,7 @@ max_ensure_room (intmax_t *m, intmax_t a, intmax_t b)
static void
restore_stack_limits (Lisp_Object data)
{
- integer_to_intmax (XCAR (data), &max_specpdl_size);
- integer_to_intmax (XCDR (data), &max_lisp_eval_depth);
+ integer_to_intmax (data, &max_lisp_eval_depth);
}
/* Call the Lisp debugger, giving it argument ARG. */
@@ -278,9 +275,6 @@ call_debugger (Lisp_Object arg)
specpdl_ref count = SPECPDL_INDEX ();
Lisp_Object val;
intmax_t old_depth = max_lisp_eval_depth;
- /* Do not allow max_specpdl_size less than actual depth (Bug#16603). */
- ptrdiff_t counti = specpdl_ref_to_count (count);
- intmax_t old_max = max (max_specpdl_size, counti);
/* The previous value of 40 is too small now that the debugger
prints using cl-prin1 instead of prin1. Printing lists nested 8
@@ -288,20 +282,8 @@ call_debugger (Lisp_Object arg)
currently requires 77 additional frames. See bug#31919. */
max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
- /* While debugging Bug#16603, previous value of 100 was found
- too small to avoid specpdl overflow in the debugger itself. */
- max_ensure_room (&max_specpdl_size, counti, 200);
-
- if (old_max == counti)
- {
- /* We can enter the debugger due to specpdl overflow (Bug#16603). */
- specpdl_ptr--;
- grow_specpdl ();
- }
-
/* Restore limits after leaving the debugger. */
- record_unwind_protect (restore_stack_limits,
- Fcons (make_int (old_max), make_int (old_depth)));
+ record_unwind_protect (restore_stack_limits, make_int (old_depth));
#ifdef HAVE_WINDOW_SYSTEM
if (display_hourglass_p)
@@ -933,12 +915,9 @@ DEFUN ("let*", FletX, SletX, 1, UNEVALLED, 0,
lexenv = Vinternal_interpreter_environment;
Lisp_Object varlist = XCAR (args);
- while (CONSP (varlist))
+ FOR_EACH_TAIL (varlist)
{
- maybe_quit ();
-
elt = XCAR (varlist);
- varlist = XCDR (varlist);
if (SYMBOLP (elt))
{
var = elt;
@@ -1752,8 +1731,6 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
{
/* Edebug takes care of restoring these variables when it exits. */
max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 20);
- ptrdiff_t counti = specpdl_ref_to_count (SPECPDL_INDEX ());
- max_ensure_room (&max_specpdl_size, counti, 40);
call2 (Vsignal_hook_function, error_symbol, data);
}
@@ -1822,8 +1799,6 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
{
max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
specpdl_ref count = SPECPDL_INDEX ();
- ptrdiff_t counti = specpdl_ref_to_count (count);
- max_ensure_room (&max_specpdl_size, counti, 200);
specbind (Qdebugger, Qdebug_early);
call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
unbind_to (count, Qnil);
@@ -1839,12 +1814,10 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
{
max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
specpdl_ref count = SPECPDL_INDEX ();
- ptrdiff_t counti = specpdl_ref_to_count (count);
AUTO_STRING (redisplay_trace, "*Redisplay_trace*");
Lisp_Object redisplay_trace_buffer;
AUTO_STRING (gap, "\n\n\n\n"); /* Separates things in *Redisplay-trace* */
Lisp_Object delayed_warning;
- max_ensure_room (&max_specpdl_size, counti, 200);
redisplay_trace_buffer = Fget_buffer_create (redisplay_trace, Qnil);
current_buffer = XBUFFER (redisplay_trace_buffer);
if (!backtrace_yet) /* Are we on the first backtrace of the command? */
@@ -2376,17 +2349,12 @@ grow_specpdl_allocation (void)
eassert (specpdl_ptr == specpdl_end);
specpdl_ref count = SPECPDL_INDEX ();
- ptrdiff_t max_size = min (max_specpdl_size, PTRDIFF_MAX - 1000);
+ ptrdiff_t max_size = PTRDIFF_MAX - 1000;
union specbinding *pdlvec = specpdl - 1;
ptrdiff_t size = specpdl_end - specpdl;
ptrdiff_t pdlvecsize = size + 1;
if (max_size <= size)
- {
- if (max_specpdl_size < 400)
- max_size = max_specpdl_size = 400;
- if (max_size <= size)
- xsignal0 (Qexcessive_variable_binding);
- }
+ xsignal0 (Qexcessive_variable_binding); /* Can't happen, essentially. */
pdlvec = xpalloc (pdlvec, &pdlvecsize, 1, max_size + 1, sizeof *specpdl);
specpdl = pdlvec + 1;
specpdl_end = specpdl + pdlvecsize - 1;
@@ -4229,22 +4197,6 @@ get_backtrace (Lisp_Object array)
void
syms_of_eval (void)
{
- DEFVAR_INT ("max-specpdl-size", max_specpdl_size,
- doc: /* Limit on number of Lisp variable bindings and `unwind-protect's.
-
-If Lisp code tries to use more bindings than this amount, an error is
-signaled.
-
-You can safely increase this variable substantially if the default
-value proves inconveniently small. However, if you increase it too
-much, Emacs could run out of memory trying to make the stack bigger.
-Note that this limit may be silently increased by the debugger if
-`debug-on-error' or `debug-on-quit' is set.
-
-\"spec\" is short for \"special variables\", i.e., dynamically bound
-variables. \"PDL\" is short for \"push-down list\", which is an old
-term for \"stack\". */);
-
DEFVAR_INT ("max-lisp-eval-depth", max_lisp_eval_depth,
doc: /* Limit on depth in `eval', `apply' and `funcall' before error.
diff --git a/src/fileio.c b/src/fileio.c
index 6efea8ac36..dd7f85ec97 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -6019,11 +6019,6 @@ DEFUN ("do-auto-save", Fdo_auto_save, Sdo_auto_save, 0, 2, "",
bool old_message_p = 0;
struct auto_save_unwind auto_save_unwind;
- intmax_t sum = INT_ADD_WRAPV (specpdl_end - specpdl, 40, &sum)
- ? INTMAX_MAX : sum;
- if (max_specpdl_size < sum)
- max_specpdl_size = sum;
-
if (minibuf_level)
no_message = Qt;
--
2.32.0 (Apple Git-132)
^ permalink raw reply related [flat|nested] 25+ messages in thread