From 185586a3377e166a5123407799ab7741d4627c52 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Wed, 9 Nov 2016 23:13:52 +0100 Subject: [PATCH] Prevent dubious argument lists See Bug#24912 and Bug#24913. * src/eval.c (funcall_lambda): Detect more dubious argument lists. * lisp/emacs-lisp/bytecomp.el (byte-compile-check-lambda-list): Detect more dubious argument lists. * test/src/eval-tests.el (eval-tests--bugs-24912-and-24913): Add unit test. --- lisp/emacs-lisp/bytecomp.el | 7 +++++-- src/eval.c | 18 +++++++++++++++--- test/src/eval-tests.el | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el index 428e21c..85daa43 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el @@ -2672,8 +2672,11 @@ byte-compile-check-lambda-list (when (cddr list) (error "Garbage following &rest VAR in lambda-list"))) ((eq arg '&optional) - (unless (cdr list) - (error "Variable name missing after &optional"))) + (when (or (null (cdr list)) + (memq (cadr list) '(&optional &rest))) + (error "Variable name missing after &optional")) + (when (memq '&optional (cddr list)) + (error "Duplicate &optional"))) ((memq arg vars) (byte-compile-warn "repeated variable %s in lambda-list" arg)) (t diff --git a/src/eval.c b/src/eval.c index caeb791..884e1eb 100644 --- a/src/eval.c +++ b/src/eval.c @@ -2888,6 +2888,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, emacs_abort (); i = optional = rest = 0; + bool previous_optional_or_rest = false; for (; CONSP (syms_left); syms_left = XCDR (syms_left)) { QUIT; @@ -2897,9 +2898,19 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, xsignal1 (Qinvalid_function, fun); if (EQ (next, Qand_rest)) - rest = 1; + { + if (rest || previous_optional_or_rest) + xsignal1 (Qinvalid_function, fun); + rest = 1; + previous_optional_or_rest = true; + } else if (EQ (next, Qand_optional)) - optional = 1; + { + if (optional || rest || previous_optional_or_rest) + xsignal1 (Qinvalid_function, fun); + optional = 1; + previous_optional_or_rest = true; + } else { Lisp_Object arg; @@ -2922,10 +2933,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, else /* Dynamically bind NEXT. */ specbind (next, arg); + previous_optional_or_rest = false; } } - if (!NILP (syms_left)) + if (!NILP (syms_left) || previous_optional_or_rest) xsignal1 (Qinvalid_function, fun); else if (i < nargs) xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs)); diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el index 75999e1..fe08506 100644 --- a/test/src/eval-tests.el +++ b/test/src/eval-tests.el @@ -32,4 +32,19 @@ ;; This should not crash. (should-error (funcall '(closure)) :type 'invalid-function)) +(ert-deftest eval-tests--bugs-24912-and-24913 () + "Checks that Emacs doesn’t accept weird argument lists. +Bug#24912 and Bug#24913." + (dolist (args '((&optional) (&rest) (&optional &rest) (&rest &optional) + (&optional &rest a) (&optional a &rest) + (&rest a &optional) (&rest &optional a) + (&optional &optional) (&optional &optional a) + (&optional a &optional b) + (&rest &rest) (&rest &rest a) + (&rest a &rest b))) + (should-error (eval `(funcall (lambda ,args)) t) :type 'invalid-function) + (should-error (byte-compile-check-lambda-list args)) + (let ((byte-compile-debug t)) + (should-error (eval `(byte-compile (lambda ,args)) t))))) + ;;; eval-tests.el ends here -- 2.8.0.rc3.226.g39d4020