[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] emacs-26 c352434 2/2: Avoid memory corruption with specpdl
From: |
Noam Postavsky |
Subject: |
[Emacs-diffs] emacs-26 c352434 2/2: Avoid memory corruption with specpdl overflow + edebug (Bug#30481) |
Date: |
Fri, 16 Feb 2018 22:24:42 -0500 (EST) |
branch: emacs-26
commit c352434ab89617b48c7c1f29342a22e5a5685504
Author: Noam Postavsky <address@hidden>
Commit: Noam Postavsky <address@hidden>
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.
---
src/eval.c | 5 ++++-
test/src/eval-tests.el | 20 ++++++++++++++++++++
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/src/eval.c b/src/eval.c
index e05a17f..ca1eb84 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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)
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el
index 201382d..e68fd13 100644
--- a/test/src/eval-tests.el
+++ b/test/src/eval-tests.el
@@ -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