diff options
| author | Philipp Stephani | 2016-11-09 23:13:52 +0100 |
|---|---|---|
| committer | Philipp Stephani | 2016-11-18 18:02:57 +0100 |
| commit | 0d913da15c094bf596dd685acecf3438228c15cf (patch) | |
| tree | 342d5e0222a35dc93cca8858317e038a76e91c27 | |
| parent | 49ac78022802dfff08367477e8d09d17d3c73e68 (diff) | |
| download | emacs-0d913da15c094bf596dd685acecf3438228c15cf.tar.gz emacs-0d913da15c094bf596dd685acecf3438228c15cf.zip | |
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.
| -rw-r--r-- | lisp/emacs-lisp/bytecomp.el | 7 | ||||
| -rw-r--r-- | src/eval.c | 18 | ||||
| -rw-r--r-- | 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 428e21c7a39..85daa43eaed 100644 --- a/lisp/emacs-lisp/bytecomp.el +++ b/lisp/emacs-lisp/bytecomp.el | |||
| @@ -2672,8 +2672,11 @@ If FORM is a lambda or a macro, byte-compile it as a function." | |||
| 2672 | (when (cddr list) | 2672 | (when (cddr list) |
| 2673 | (error "Garbage following &rest VAR in lambda-list"))) | 2673 | (error "Garbage following &rest VAR in lambda-list"))) |
| 2674 | ((eq arg '&optional) | 2674 | ((eq arg '&optional) |
| 2675 | (unless (cdr list) | 2675 | (when (or (null (cdr list)) |
| 2676 | (error "Variable name missing after &optional"))) | 2676 | (memq (cadr list) '(&optional &rest))) |
| 2677 | (error "Variable name missing after &optional")) | ||
| 2678 | (when (memq '&optional (cddr list)) | ||
| 2679 | (error "Duplicate &optional"))) | ||
| 2677 | ((memq arg vars) | 2680 | ((memq arg vars) |
| 2678 | (byte-compile-warn "repeated variable %s in lambda-list" arg)) | 2681 | (byte-compile-warn "repeated variable %s in lambda-list" arg)) |
| 2679 | (t | 2682 | (t |
diff --git a/src/eval.c b/src/eval.c index caeb791c19b..884e1ebfb89 100644 --- a/src/eval.c +++ b/src/eval.c | |||
| @@ -2888,6 +2888,7 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, | |||
| 2888 | emacs_abort (); | 2888 | emacs_abort (); |
| 2889 | 2889 | ||
| 2890 | i = optional = rest = 0; | 2890 | i = optional = rest = 0; |
| 2891 | bool previous_optional_or_rest = false; | ||
| 2891 | for (; CONSP (syms_left); syms_left = XCDR (syms_left)) | 2892 | for (; CONSP (syms_left); syms_left = XCDR (syms_left)) |
| 2892 | { | 2893 | { |
| 2893 | QUIT; | 2894 | QUIT; |
| @@ -2897,9 +2898,19 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, | |||
| 2897 | xsignal1 (Qinvalid_function, fun); | 2898 | xsignal1 (Qinvalid_function, fun); |
| 2898 | 2899 | ||
| 2899 | if (EQ (next, Qand_rest)) | 2900 | if (EQ (next, Qand_rest)) |
| 2900 | rest = 1; | 2901 | { |
| 2902 | if (rest || previous_optional_or_rest) | ||
| 2903 | xsignal1 (Qinvalid_function, fun); | ||
| 2904 | rest = 1; | ||
| 2905 | previous_optional_or_rest = true; | ||
| 2906 | } | ||
| 2901 | else if (EQ (next, Qand_optional)) | 2907 | else if (EQ (next, Qand_optional)) |
| 2902 | optional = 1; | 2908 | { |
| 2909 | if (optional || rest || previous_optional_or_rest) | ||
| 2910 | xsignal1 (Qinvalid_function, fun); | ||
| 2911 | optional = 1; | ||
| 2912 | previous_optional_or_rest = true; | ||
| 2913 | } | ||
| 2903 | else | 2914 | else |
| 2904 | { | 2915 | { |
| 2905 | Lisp_Object arg; | 2916 | Lisp_Object arg; |
| @@ -2922,10 +2933,11 @@ funcall_lambda (Lisp_Object fun, ptrdiff_t nargs, | |||
| 2922 | else | 2933 | else |
| 2923 | /* Dynamically bind NEXT. */ | 2934 | /* Dynamically bind NEXT. */ |
| 2924 | specbind (next, arg); | 2935 | specbind (next, arg); |
| 2936 | previous_optional_or_rest = false; | ||
| 2925 | } | 2937 | } |
| 2926 | } | 2938 | } |
| 2927 | 2939 | ||
| 2928 | if (!NILP (syms_left)) | 2940 | if (!NILP (syms_left) || previous_optional_or_rest) |
| 2929 | xsignal1 (Qinvalid_function, fun); | 2941 | xsignal1 (Qinvalid_function, fun); |
| 2930 | else if (i < nargs) | 2942 | else if (i < nargs) |
| 2931 | xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs)); | 2943 | xsignal2 (Qwrong_number_of_arguments, fun, make_number (nargs)); |
diff --git a/test/src/eval-tests.el b/test/src/eval-tests.el index 75999e1a25a..fe08506ed25 100644 --- a/test/src/eval-tests.el +++ b/test/src/eval-tests.el | |||
| @@ -32,4 +32,19 @@ | |||
| 32 | ;; This should not crash. | 32 | ;; This should not crash. |
| 33 | (should-error (funcall '(closure)) :type 'invalid-function)) | 33 | (should-error (funcall '(closure)) :type 'invalid-function)) |
| 34 | 34 | ||
| 35 | (ert-deftest eval-tests--bugs-24912-and-24913 () | ||
| 36 | "Checks that Emacs doesn’t accept weird argument lists. | ||
| 37 | Bug#24912 and Bug#24913." | ||
| 38 | (dolist (args '((&optional) (&rest) (&optional &rest) (&rest &optional) | ||
| 39 | (&optional &rest a) (&optional a &rest) | ||
| 40 | (&rest a &optional) (&rest &optional a) | ||
| 41 | (&optional &optional) (&optional &optional a) | ||
| 42 | (&optional a &optional b) | ||
| 43 | (&rest &rest) (&rest &rest a) | ||
| 44 | (&rest a &rest b))) | ||
| 45 | (should-error (eval `(funcall (lambda ,args)) t) :type 'invalid-function) | ||
| 46 | (should-error (byte-compile-check-lambda-list args)) | ||
| 47 | (let ((byte-compile-debug t)) | ||
| 48 | (should-error (eval `(byte-compile (lambda ,args)) t))))) | ||
| 49 | |||
| 35 | ;;; eval-tests.el ends here | 50 | ;;; eval-tests.el ends here |