diff options
author | Philipp Stephani <phst@google.com> | 2020-07-25 23:04:05 +0200 |
---|---|---|
committer | Philipp Stephani <phst@google.com> | 2020-07-25 23:04:05 +0200 |
commit | 6355a3ec62f43c9b99d483982ff851d32dd78891 (patch) | |
tree | 2a9896b373c7e713c8ec504a464d5401e8134ab8 /src/emacs-module.c | |
parent | 609cbd63c31a21ca521507695abeda1203134c99 (diff) | |
download | emacs-6355a3ec62f43c9b99d483982ff851d32dd78891.tar.gz |
Fix subtle bug when checking liveness of module values.
We can't simply look up the Lisp object in the global reference table
because an invalid local and a valid global reference might refer to
the same object. Instead, we have to test the address of the global
reference against the stored references.
* src/emacs-module.c (module_global_reference_p): New helper function.
(value_to_lisp): Use it.
* test/data/emacs-module/mod-test.c
(Fmod_test_invalid_store_copy): New test module function.
(emacs_module_init): Export it.
* test/src/emacs-module-tests.el
(module--test-assertions--load-non-live-object-with-global-copy):
New unit test.
Diffstat (limited to 'src/emacs-module.c')
-rw-r--r-- | src/emacs-module.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/src/emacs-module.c b/src/emacs-module.c index c47ea9c1950..02563a4b8b5 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -78,6 +78,7 @@ To add a new module function, proceed as follows: #include "emacs-module.h" #include <stdarg.h> +#include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> @@ -400,6 +401,28 @@ XMODULE_GLOBAL_REFERENCE (Lisp_Object o) return XUNTAG (o, Lisp_Vectorlike, struct module_global_reference); } +/* Returns whether V is a global reference. Only used to check module + assertions. If V is not a global reference, increment *N by the + number of global references (for debugging output). */ + +static bool +module_global_reference_p (emacs_value v, ptrdiff_t *n) +{ + struct Lisp_Hash_Table *h = XHASH_TABLE (Vmodule_refs_hash); + /* Note that we can't use `hash_lookup' because V might be a local + reference that's identical to some global reference. */ + for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) + { + if (!EQ (HASH_KEY (h, i), Qunbound) + && &XMODULE_GLOBAL_REFERENCE (HASH_VALUE (h, i))->value == v) + return true; + } + /* Only used for debugging, so we don't care about overflow, just + make sure the operation is defined. */ + INT_ADD_WRAPV (*n, h->count, n); + return false; +} + static emacs_value module_make_global_ref (emacs_env *env, emacs_value value) { @@ -1277,10 +1300,8 @@ value_to_lisp (emacs_value v) ++num_environments; } /* Also check global values. */ - struct Lisp_Hash_Table *h = XHASH_TABLE (Vmodule_refs_hash); - if (hash_lookup (h, v->v, NULL) != -1) + if (module_global_reference_p (v, &num_values)) goto ok; - INT_ADD_WRAPV (num_values, h->count, &num_values); module_abort (("Emacs value not found in %"pD"d values " "of %"pD"d environments"), num_values, num_environments); |