Avoid memory corruption with specpdl overflow + edebug (Bug#30481)
If grow_specpdl fails due to outgrowing max_specpdl_size, it will signal an error *before* growing the specpdl array. Therefore, when handling the signal, specpdl_ptr points past the end of the specpdl array and any further use of of specpdl before unwinding (e.g., if edebug binds signal-hook-function) will cause memory corruption. * src/eval.c (signal_or_quit): Don't call `signal-hook-function' if the specpdl_ptr is already past the end of the specpdl array. * test/src/eval-tests.el (eval-tests--exceed-specbind-limit) (eval-exceed-specbind-with-signal-hook): New test & helper function.
This commit is contained in:
parent
593bbdaf0b
commit
c352434ab8
2 changed files with 24 additions and 1 deletions
|
@ -1553,7 +1553,10 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object data, bool keyboard_quit)
|
||||||
|
|
||||||
/* This hook is used by edebug. */
|
/* This hook is used by edebug. */
|
||||||
if (! NILP (Vsignal_hook_function)
|
if (! NILP (Vsignal_hook_function)
|
||||||
&& ! NILP (error_symbol))
|
&& ! NILP (error_symbol)
|
||||||
|
/* Don't try to call a lisp function if we've already overflowed
|
||||||
|
the specpdl stack. */
|
||||||
|
&& specpdl_ptr < specpdl + specpdl_size)
|
||||||
{
|
{
|
||||||
/* Edebug takes care of restoring these variables when it exits. */
|
/* Edebug takes care of restoring these variables when it exits. */
|
||||||
if (lisp_eval_depth + 20 > max_lisp_eval_depth)
|
if (lisp_eval_depth + 20 > max_lisp_eval_depth)
|
||||||
|
|
|
@ -79,4 +79,24 @@ Bug#24912 and Bug#24913."
|
||||||
(let ((clauses (list '((progn (setcdr clauses "ouch") nil)))))
|
(let ((clauses (list '((progn (setcdr clauses "ouch") nil)))))
|
||||||
(should-error (eval (cons 'cond clauses)))))
|
(should-error (eval (cons 'cond clauses)))))
|
||||||
|
|
||||||
|
(defun eval-tests--exceed-specbind-limit ()
|
||||||
|
(defvar eval-tests--var1)
|
||||||
|
(defvar eval-tests--var2)
|
||||||
|
;; Bind two variables, to make extra sure we hit the
|
||||||
|
;; `max-specpdl-size' limit before the `max-lisp-eval-depth' limit.
|
||||||
|
(let ((eval-tests--var1 1)
|
||||||
|
(eval-tests--var2 2))
|
||||||
|
;; Recurse until we hit the limit.
|
||||||
|
(eval-tests--exceed-specbind-limit)))
|
||||||
|
|
||||||
|
(ert-deftest eval-exceed-specbind-with-signal-hook ()
|
||||||
|
"Test for Bug#30481.
|
||||||
|
Check that Emacs doesn't crash when exceeding specbind limit with
|
||||||
|
`signal-hook-function' bound. NOTE: Without the fix for
|
||||||
|
Bug#30481, this test can appear to pass, but cause a
|
||||||
|
crash/abort/malloc assert failure on the next test."
|
||||||
|
(let ((max-specpdl-size (/ max-lisp-eval-depth 2))
|
||||||
|
(signal-hook-function #'ignore))
|
||||||
|
(should-error (eval-tests--exceed-specbind-limit))))
|
||||||
|
|
||||||
;;; eval-tests.el ends here
|
;;; eval-tests.el ends here
|
||||||
|
|
Loading…
Add table
Reference in a new issue