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. */
|
||||
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. */
|
||||
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)))))
|
||||
(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
|
||||
|
|
Loading…
Add table
Reference in a new issue