diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2018-06-09 17:56:29 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2018-06-09 17:57:29 -0700 |
commit | 3e3e23fb88fdc19e859c0aa2ab51b86afd323c71 (patch) | |
tree | b579820537e9996b2c7f35bac95eff2f1700c178 /src/json.c | |
parent | d12924cacb86c53a0547f73af35169db8e44d628 (diff) | |
download | emacs-3e3e23fb88fdc19e859c0aa2ab51b86afd323c71.tar.gz |
Fix pointer misuse in JSON parser
* src/json.c (lisp_to_json_toplevel_1): Fix pointer misuse not
caught by C type checking (json_t ** converted to void * where
the program expected json_t *). Bug caught on Fedora 28 x86-64 via
'./configure CFLAGS="-g3 -O2 -fsanitize=address" CANNOT_DUMP=yes'.
Avoid similar problems in the future by rewriting to use
json_t * instead of json_t **.
Diffstat (limited to 'src/json.c')
-rw-r--r-- | src/json.c | 60 |
1 files changed, 28 insertions, 32 deletions
diff --git a/src/json.c b/src/json.c index afb81587a47..c28e14d63c6 100644 --- a/src/json.c +++ b/src/json.c @@ -327,36 +327,35 @@ json_check_utf8 (Lisp_Object string) static json_t *lisp_to_json (Lisp_Object); -/* Convert a Lisp object to a toplevel JSON object (array or object). - This returns Lisp_Object so we can use unbind_to. The return value - is always nil. */ +/* Convert a Lisp object to a toplevel JSON object (array or object). */ -static _GL_ARG_NONNULL ((2)) Lisp_Object -lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) +static json_t * +lisp_to_json_toplevel_1 (Lisp_Object lisp) { + json_t *json; + ptrdiff_t count; + if (VECTORP (lisp)) { ptrdiff_t size = ASIZE (lisp); - *json = json_check (json_array ()); - ptrdiff_t count = SPECPDL_INDEX (); + json = json_check (json_array ()); + count = SPECPDL_INDEX (); record_unwind_protect_ptr (json_release_object, json); for (ptrdiff_t i = 0; i < size; ++i) { int status - = json_array_append_new (*json, lisp_to_json (AREF (lisp, i))); + = json_array_append_new (json, lisp_to_json (AREF (lisp, i))); if (status == -1) json_out_of_memory (); } - eassert (json_array_size (*json) == size); - clear_unwind_protect (count); - return unbind_to (count, Qnil); + eassert (json_array_size (json) == size); } else if (HASH_TABLE_P (lisp)) { struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); - *json = json_check (json_object ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, *json); + json = json_check (json_object ()); + count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, json); for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) if (!NILP (HASH_HASH (h, i))) { @@ -367,9 +366,9 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) const char *key_str = SSDATA (key); /* Reject duplicate keys. These are possible if the hash table test is not `equal'. */ - if (json_object_get (*json, key_str) != NULL) + if (json_object_get (json, key_str) != NULL) wrong_type_argument (Qjson_value_p, lisp); - int status = json_object_set_new (*json, key_str, + int status = json_object_set_new (json, key_str, lisp_to_json (HASH_VALUE (h, i))); if (status == -1) { @@ -379,20 +378,15 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) json_out_of_memory (); } } - clear_unwind_protect (count); - return unbind_to (count, Qnil); } else if (NILP (lisp)) - { - *json = json_check (json_object ()); - return Qnil; - } + return json_check (json_object ()); else if (CONSP (lisp)) { Lisp_Object tail = lisp; - *json = json_check (json_object ()); - ptrdiff_t count = SPECPDL_INDEX (); - record_unwind_protect_ptr (json_release_object, *json); + json = json_check (json_object ()); + count = SPECPDL_INDEX (); + record_unwind_protect_ptr (json_release_object, json); bool is_plist = !CONSP (XCAR (tail)); FOR_EACH_TAIL (tail) { @@ -427,19 +421,22 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) key_str = &key_str[1]; } /* Only add element if key is not already present. */ - if (json_object_get (*json, key_str) == NULL) + if (json_object_get (json, key_str) == NULL) { int status - = json_object_set_new (*json, key_str, lisp_to_json (value)); + = json_object_set_new (json, key_str, lisp_to_json (value)); if (status == -1) json_out_of_memory (); } } CHECK_LIST_END (tail, lisp); - clear_unwind_protect (count); - return unbind_to (count, Qnil); } - wrong_type_argument (Qjson_value_p, lisp); + else + wrong_type_argument (Qjson_value_p, lisp); + + clear_unwind_protect (count); + unbind_to (count, Qnil); + return json; } /* Convert LISP to a toplevel JSON object (array or object). Signal @@ -451,8 +448,7 @@ lisp_to_json_toplevel (Lisp_Object lisp) { if (++lisp_eval_depth > max_lisp_eval_depth) xsignal0 (Qjson_object_too_deep); - json_t *json; - lisp_to_json_toplevel_1 (lisp, &json); + json_t *json = lisp_to_json_toplevel_1 (lisp); --lisp_eval_depth; return json; } |