diff options
| author | Philipp Stephani | 2017-07-04 22:50:46 +0200 |
|---|---|---|
| committer | Philipp Stephani | 2017-07-08 15:25:01 +0200 |
| commit | b7dab24b7953f7a31b806f83e15043c94aaa7745 (patch) | |
| tree | fc31284ef0fac82accddc573069652b1c8adccf0 /test/src | |
| parent | a87d767c7acc43b3679d87d2d225b1edeb69326c (diff) | |
| download | emacs-b7dab24b7953f7a31b806f83e15043c94aaa7745.tar.gz emacs-b7dab24b7953f7a31b806f83e15043c94aaa7745.zip | |
Module assertions: check for garbage collections
It's technically possible to write a user pointer finalizer that calls
into Emacs module functions. This would be disastrous because it
would allow arbitrary Lisp code to run during garbage collection.
Therefore extend the module assertions to check for this case.
* src/emacs-module.c (module_assert_thread): Also check whether a
garbage collection is in progress.
* test/data/emacs-module/mod-test.c (invalid_finalizer)
(Fmod_test_invalid_finalizer): New test module functions.
(emacs_module_init): Register new test function.
* test/src/emacs-module-tests.el (module--test-assertion)
(module--with-temp-directory): New helper macros.
(module--test-assertions--load-non-live-object): Rename existing
unit test, use helper macros.
(module--test-assertions--call-emacs-from-gc): New unit test.
Diffstat (limited to 'test/src')
| -rw-r--r-- | test/src/emacs-module-tests.el | 87 |
1 files changed, 58 insertions, 29 deletions
diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el index a4994b6223b..988a7a178c6 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el | |||
| @@ -182,37 +182,66 @@ changes." | |||
| 182 | (should (equal (help-function-arglist #'mod-test-sum) | 182 | (should (equal (help-function-arglist #'mod-test-sum) |
| 183 | '(arg1 arg2)))) | 183 | '(arg1 arg2)))) |
| 184 | 184 | ||
| 185 | (ert-deftest module--test-assertions () | 185 | (defmacro module--with-temp-directory (name &rest body) |
| 186 | "Check that -module-assertions work." | 186 | "Bind NAME to the name of a temporary directory and evaluate BODY. |
| 187 | NAME must be a symbol. Delete the temporary directory after BODY | ||
| 188 | exits normally or non-locally. NAME will be bound to the | ||
| 189 | directory name (not the directory file name) of the temporary | ||
| 190 | directory." | ||
| 191 | (declare (indent 1)) | ||
| 192 | (cl-check-type name symbol) | ||
| 193 | `(let ((,name (file-name-as-directory | ||
| 194 | (make-temp-file "emacs-module-test" :directory)))) | ||
| 195 | (unwind-protect | ||
| 196 | (progn ,@body) | ||
| 197 | (delete-directory ,name :recursive)))) | ||
| 198 | |||
| 199 | (defmacro module--test-assertion (pattern &rest body) | ||
| 200 | "Test that PATTERN matches the assertion triggered by BODY. | ||
| 201 | Run Emacs as a subprocess, load the test module `mod-test-file', | ||
| 202 | and evaluate BODY. Verify that Emacs aborts and prints a module | ||
| 203 | assertion message that matches PATTERN. PATTERN is evaluated and | ||
| 204 | must evaluate to a regular expression string." | ||
| 205 | (declare (indent 1)) | ||
| 206 | ;; To contain any core dumps. | ||
| 207 | `(module--with-temp-directory tempdir | ||
| 208 | (with-temp-buffer | ||
| 209 | (let* ((default-directory tempdir) | ||
| 210 | (status (call-process mod-test-emacs nil t nil | ||
| 211 | "-batch" "-Q" "-module-assertions" "-eval" | ||
| 212 | ,(prin1-to-string | ||
| 213 | `(progn | ||
| 214 | (require 'mod-test ,mod-test-file) | ||
| 215 | ,@body))))) | ||
| 216 | (should (stringp status)) | ||
| 217 | ;; eg "Aborted" or "Abort trap: 6" | ||
| 218 | (should (string-prefix-p "Abort" status)) | ||
| 219 | (search-backward "Emacs module assertion: ") | ||
| 220 | (goto-char (match-end 0)) | ||
| 221 | (should (string-match-p ,pattern | ||
| 222 | (buffer-substring-no-properties | ||
| 223 | (point) (point-max)))))))) | ||
| 224 | |||
| 225 | (ert-deftest module--test-assertions--load-non-live-object () | ||
| 226 | "Check that -module-assertions verify that non-live objects | ||
| 227 | aren’t accessed." | ||
| 187 | (skip-unless (file-executable-p mod-test-emacs)) | 228 | (skip-unless (file-executable-p mod-test-emacs)) |
| 188 | ;; This doesn’t yet cause undefined behavior. | 229 | ;; This doesn’t yet cause undefined behavior. |
| 189 | (should (eq (mod-test-invalid-store) 123)) | 230 | (should (eq (mod-test-invalid-store) 123)) |
| 190 | ;; To contain any core dumps. | 231 | (module--test-assertion (rx "Emacs value not found in " |
| 191 | (let ((tempdir (make-temp-file "emacs-module-test" t))) | 232 | (+ digit) " values of " |
| 192 | (unwind-protect | 233 | (+ digit) " environments\n" eos) |
| 193 | (with-temp-buffer | 234 | ;; Storing and reloading a local value causes undefined behavior, |
| 194 | (should (string-match-p | 235 | ;; which should be detected by the module assertions. |
| 195 | "Abort" ; eg "Aborted" or "Abort trap: 6" | 236 | (mod-test-invalid-store) |
| 196 | (let ((default-directory tempdir)) | 237 | (mod-test-invalid-load))) |
| 197 | (call-process mod-test-emacs nil t nil | 238 | |
| 198 | "-batch" "-Q" "-module-assertions" "-eval" | 239 | (ert-deftest module--test-assertions--call-emacs-from-gc () |
| 199 | (prin1-to-string | 240 | "Check that -module-assertions prevents calling Emacs functions |
| 200 | `(progn | 241 | during garbage collection." |
| 201 | (require 'mod-test ,mod-test-file) | 242 | (skip-unless (file-executable-p mod-test-emacs)) |
| 202 | ;; Storing and reloading a local | 243 | (module--test-assertion |
| 203 | ;; value causes undefined behavior, | 244 | (rx "Module function called during garbage collection\n" eos) |
| 204 | ;; which should be detected by the | 245 | (mod-test-invalid-finalizer))) |
| 205 | ;; module assertions. | ||
| 206 | (mod-test-invalid-store) | ||
| 207 | (mod-test-invalid-load))))))) | ||
| 208 | (search-backward "Emacs module assertion:") | ||
| 209 | (should (string-match-p (rx bos "Emacs module assertion: " | ||
| 210 | "Emacs value not found in " | ||
| 211 | (+ digit) " values of " | ||
| 212 | (+ digit) " environments" eos) | ||
| 213 | (buffer-substring-no-properties | ||
| 214 | (line-beginning-position) | ||
| 215 | (line-end-position))))) | ||
| 216 | (delete-directory tempdir t)))) | ||
| 217 | 246 | ||
| 218 | ;;; emacs-module-tests.el ends here | 247 | ;;; emacs-module-tests.el ends here |