diff options
| author | Paul Eggert | 2018-06-09 17:56:29 -0700 |
|---|---|---|
| committer | Paul Eggert | 2018-06-09 17:57:29 -0700 |
| commit | 3e3e23fb88fdc19e859c0aa2ab51b86afd323c71 (patch) | |
| tree | b579820537e9996b2c7f35bac95eff2f1700c178 /src | |
| parent | d12924cacb86c53a0547f73af35169db8e44d628 (diff) | |
| download | emacs-3e3e23fb88fdc19e859c0aa2ab51b86afd323c71.tar.gz emacs-3e3e23fb88fdc19e859c0aa2ab51b86afd323c71.zip | |
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')
| -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) | |||
| 327 | 327 | ||
| 328 | static json_t *lisp_to_json (Lisp_Object); | 328 | static json_t *lisp_to_json (Lisp_Object); |
| 329 | 329 | ||
| 330 | /* Convert a Lisp object to a toplevel JSON object (array or object). | 330 | /* Convert a Lisp object to a toplevel JSON object (array or object). */ |
| 331 | This returns Lisp_Object so we can use unbind_to. The return value | ||
| 332 | is always nil. */ | ||
| 333 | 331 | ||
| 334 | static _GL_ARG_NONNULL ((2)) Lisp_Object | 332 | static json_t * |
| 335 | lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) | 333 | lisp_to_json_toplevel_1 (Lisp_Object lisp) |
| 336 | { | 334 | { |
| 335 | json_t *json; | ||
| 336 | ptrdiff_t count; | ||
| 337 | |||
| 337 | if (VECTORP (lisp)) | 338 | if (VECTORP (lisp)) |
| 338 | { | 339 | { |
| 339 | ptrdiff_t size = ASIZE (lisp); | 340 | ptrdiff_t size = ASIZE (lisp); |
| 340 | *json = json_check (json_array ()); | 341 | json = json_check (json_array ()); |
| 341 | ptrdiff_t count = SPECPDL_INDEX (); | 342 | count = SPECPDL_INDEX (); |
| 342 | record_unwind_protect_ptr (json_release_object, json); | 343 | record_unwind_protect_ptr (json_release_object, json); |
| 343 | for (ptrdiff_t i = 0; i < size; ++i) | 344 | for (ptrdiff_t i = 0; i < size; ++i) |
| 344 | { | 345 | { |
| 345 | int status | 346 | int status |
| 346 | = json_array_append_new (*json, lisp_to_json (AREF (lisp, i))); | 347 | = json_array_append_new (json, lisp_to_json (AREF (lisp, i))); |
| 347 | if (status == -1) | 348 | if (status == -1) |
| 348 | json_out_of_memory (); | 349 | json_out_of_memory (); |
| 349 | } | 350 | } |
| 350 | eassert (json_array_size (*json) == size); | 351 | eassert (json_array_size (json) == size); |
| 351 | clear_unwind_protect (count); | ||
| 352 | return unbind_to (count, Qnil); | ||
| 353 | } | 352 | } |
| 354 | else if (HASH_TABLE_P (lisp)) | 353 | else if (HASH_TABLE_P (lisp)) |
| 355 | { | 354 | { |
| 356 | struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); | 355 | struct Lisp_Hash_Table *h = XHASH_TABLE (lisp); |
| 357 | *json = json_check (json_object ()); | 356 | json = json_check (json_object ()); |
| 358 | ptrdiff_t count = SPECPDL_INDEX (); | 357 | count = SPECPDL_INDEX (); |
| 359 | record_unwind_protect_ptr (json_release_object, *json); | 358 | record_unwind_protect_ptr (json_release_object, json); |
| 360 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) | 359 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) |
| 361 | if (!NILP (HASH_HASH (h, i))) | 360 | if (!NILP (HASH_HASH (h, i))) |
| 362 | { | 361 | { |
| @@ -367,9 +366,9 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) | |||
| 367 | const char *key_str = SSDATA (key); | 366 | const char *key_str = SSDATA (key); |
| 368 | /* Reject duplicate keys. These are possible if the hash | 367 | /* Reject duplicate keys. These are possible if the hash |
| 369 | table test is not `equal'. */ | 368 | table test is not `equal'. */ |
| 370 | if (json_object_get (*json, key_str) != NULL) | 369 | if (json_object_get (json, key_str) != NULL) |
| 371 | wrong_type_argument (Qjson_value_p, lisp); | 370 | wrong_type_argument (Qjson_value_p, lisp); |
| 372 | int status = json_object_set_new (*json, key_str, | 371 | int status = json_object_set_new (json, key_str, |
| 373 | lisp_to_json (HASH_VALUE (h, i))); | 372 | lisp_to_json (HASH_VALUE (h, i))); |
| 374 | if (status == -1) | 373 | if (status == -1) |
| 375 | { | 374 | { |
| @@ -379,20 +378,15 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) | |||
| 379 | json_out_of_memory (); | 378 | json_out_of_memory (); |
| 380 | } | 379 | } |
| 381 | } | 380 | } |
| 382 | clear_unwind_protect (count); | ||
| 383 | return unbind_to (count, Qnil); | ||
| 384 | } | 381 | } |
| 385 | else if (NILP (lisp)) | 382 | else if (NILP (lisp)) |
| 386 | { | 383 | return json_check (json_object ()); |
| 387 | *json = json_check (json_object ()); | ||
| 388 | return Qnil; | ||
| 389 | } | ||
| 390 | else if (CONSP (lisp)) | 384 | else if (CONSP (lisp)) |
| 391 | { | 385 | { |
| 392 | Lisp_Object tail = lisp; | 386 | Lisp_Object tail = lisp; |
| 393 | *json = json_check (json_object ()); | 387 | json = json_check (json_object ()); |
| 394 | ptrdiff_t count = SPECPDL_INDEX (); | 388 | count = SPECPDL_INDEX (); |
| 395 | record_unwind_protect_ptr (json_release_object, *json); | 389 | record_unwind_protect_ptr (json_release_object, json); |
| 396 | bool is_plist = !CONSP (XCAR (tail)); | 390 | bool is_plist = !CONSP (XCAR (tail)); |
| 397 | FOR_EACH_TAIL (tail) | 391 | FOR_EACH_TAIL (tail) |
| 398 | { | 392 | { |
| @@ -427,19 +421,22 @@ lisp_to_json_toplevel_1 (Lisp_Object lisp, json_t **json) | |||
| 427 | key_str = &key_str[1]; | 421 | key_str = &key_str[1]; |
| 428 | } | 422 | } |
| 429 | /* Only add element if key is not already present. */ | 423 | /* Only add element if key is not already present. */ |
| 430 | if (json_object_get (*json, key_str) == NULL) | 424 | if (json_object_get (json, key_str) == NULL) |
| 431 | { | 425 | { |
| 432 | int status | 426 | int status |
| 433 | = json_object_set_new (*json, key_str, lisp_to_json (value)); | 427 | = json_object_set_new (json, key_str, lisp_to_json (value)); |
| 434 | if (status == -1) | 428 | if (status == -1) |
| 435 | json_out_of_memory (); | 429 | json_out_of_memory (); |
| 436 | } | 430 | } |
| 437 | } | 431 | } |
| 438 | CHECK_LIST_END (tail, lisp); | 432 | CHECK_LIST_END (tail, lisp); |
| 439 | clear_unwind_protect (count); | ||
| 440 | return unbind_to (count, Qnil); | ||
| 441 | } | 433 | } |
| 442 | wrong_type_argument (Qjson_value_p, lisp); | 434 | else |
| 435 | wrong_type_argument (Qjson_value_p, lisp); | ||
| 436 | |||
| 437 | clear_unwind_protect (count); | ||
| 438 | unbind_to (count, Qnil); | ||
| 439 | return json; | ||
| 443 | } | 440 | } |
| 444 | 441 | ||
| 445 | /* Convert LISP to a toplevel JSON object (array or object). Signal | 442 | /* Convert LISP to a toplevel JSON object (array or object). Signal |
| @@ -451,8 +448,7 @@ lisp_to_json_toplevel (Lisp_Object lisp) | |||
| 451 | { | 448 | { |
| 452 | if (++lisp_eval_depth > max_lisp_eval_depth) | 449 | if (++lisp_eval_depth > max_lisp_eval_depth) |
| 453 | xsignal0 (Qjson_object_too_deep); | 450 | xsignal0 (Qjson_object_too_deep); |
| 454 | json_t *json; | 451 | json_t *json = lisp_to_json_toplevel_1 (lisp); |
| 455 | lisp_to_json_toplevel_1 (lisp, &json); | ||
| 456 | --lisp_eval_depth; | 452 | --lisp_eval_depth; |
| 457 | return json; | 453 | return json; |
| 458 | } | 454 | } |