comparison src/json.c @ 10559:4d8be28b5913 v8.0.0169

patch 8.0.0169: json_decode() may run out of stack space commit https://github.com/vim/vim/commit/8b2f19536ff979046f0d241850f4176a1ce4bca9 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Jan 10 19:44:18 2017 +0100 patch 8.0.0169: json_decode() may run out of stack space Problem: For complicated string json_decode() may run out of stack space. Solution: Change the recursive solution into an iterative solution.
author Christian Brabandt <cb@256bit.org>
date Tue, 10 Jan 2017 19:45:03 +0100
parents f83b6a0b6148
children e025378406d1
comparison
equal deleted inserted replaced
10558:eb3603e558be 10559:4d8be28b5913
376 } 376 }
377 fill_numbuflen(reader); 377 fill_numbuflen(reader);
378 } 378 }
379 379
380 static int 380 static int
381 json_decode_array(js_read_T *reader, typval_T *res, int options)
382 {
383 char_u *p;
384 typval_T item;
385 listitem_T *li;
386 int ret;
387
388 if (res != NULL && rettv_list_alloc(res) == FAIL)
389 {
390 res->v_type = VAR_SPECIAL;
391 res->vval.v_number = VVAL_NONE;
392 return FAIL;
393 }
394 ++reader->js_used; /* consume the '[' */
395
396 while (TRUE)
397 {
398 json_skip_white(reader);
399 p = reader->js_buf + reader->js_used;
400 if (*p == NUL)
401 return MAYBE;
402 if (*p == ']')
403 {
404 ++reader->js_used; /* consume the ']' */
405 break;
406 }
407
408 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
409 if (ret != OK)
410 return ret;
411 if (res != NULL)
412 {
413 li = listitem_alloc();
414 if (li == NULL)
415 {
416 clear_tv(&item);
417 return FAIL;
418 }
419 li->li_tv = item;
420 list_append(res->vval.v_list, li);
421 }
422
423 json_skip_white(reader);
424 p = reader->js_buf + reader->js_used;
425 if (*p == ',')
426 ++reader->js_used;
427 else if (*p != ']')
428 {
429 if (*p == NUL)
430 return MAYBE;
431 EMSG(_(e_invarg));
432 return FAIL;
433 }
434 }
435 return OK;
436 }
437
438 static int
439 json_decode_object(js_read_T *reader, typval_T *res, int options)
440 {
441 char_u *p;
442 typval_T tvkey;
443 typval_T item;
444 dictitem_T *di;
445 char_u buf[NUMBUFLEN];
446 char_u *key = NULL;
447 int ret;
448
449 if (res != NULL && rettv_dict_alloc(res) == FAIL)
450 {
451 res->v_type = VAR_SPECIAL;
452 res->vval.v_number = VVAL_NONE;
453 return FAIL;
454 }
455 ++reader->js_used; /* consume the '{' */
456
457 while (TRUE)
458 {
459 json_skip_white(reader);
460 p = reader->js_buf + reader->js_used;
461 if (*p == NUL)
462 return MAYBE;
463 if (*p == '}')
464 {
465 ++reader->js_used; /* consume the '}' */
466 break;
467 }
468
469 if ((options & JSON_JS) && reader->js_buf[reader->js_used] != '"')
470 {
471 /* accept a key that is not in quotes */
472 key = p = reader->js_buf + reader->js_used;
473 while (*p != NUL && *p != ':' && *p > ' ')
474 ++p;
475 tvkey.v_type = VAR_STRING;
476 tvkey.vval.v_string = vim_strnsave(key, (int)(p - key));
477 reader->js_used += (int)(p - key);
478 key = tvkey.vval.v_string;
479 }
480 else
481 {
482 ret = json_decode_item(reader, res == NULL ? NULL : &tvkey,
483 options);
484 if (ret != OK)
485 return ret;
486 if (res != NULL)
487 {
488 key = get_tv_string_buf_chk(&tvkey, buf);
489 if (key == NULL || *key == NUL)
490 {
491 clear_tv(&tvkey);
492 EMSG(_(e_invarg));
493 return FAIL;
494 }
495 }
496 }
497
498 json_skip_white(reader);
499 p = reader->js_buf + reader->js_used;
500 if (*p != ':')
501 {
502 if (res != NULL)
503 clear_tv(&tvkey);
504 if (*p == NUL)
505 return MAYBE;
506 EMSG(_(e_invarg));
507 return FAIL;
508 }
509 ++reader->js_used;
510 json_skip_white(reader);
511
512 ret = json_decode_item(reader, res == NULL ? NULL : &item, options);
513 if (ret != OK)
514 {
515 if (res != NULL)
516 clear_tv(&tvkey);
517 return ret;
518 }
519
520 if (res != NULL && dict_find(res->vval.v_dict, key, -1) != NULL)
521 {
522 EMSG2(_("E937: Duplicate key in JSON: \"%s\""), key);
523 clear_tv(&tvkey);
524 clear_tv(&item);
525 return FAIL;
526 }
527
528 if (res != NULL)
529 {
530 di = dictitem_alloc(key);
531 clear_tv(&tvkey);
532 if (di == NULL)
533 {
534 clear_tv(&item);
535 return FAIL;
536 }
537 di->di_tv = item;
538 di->di_tv.v_lock = 0;
539 if (dict_add(res->vval.v_dict, di) == FAIL)
540 {
541 dictitem_free(di);
542 return FAIL;
543 }
544 }
545
546 json_skip_white(reader);
547 p = reader->js_buf + reader->js_used;
548 if (*p == ',')
549 ++reader->js_used;
550 else if (*p != '}')
551 {
552 if (*p == NUL)
553 return MAYBE;
554 EMSG(_(e_invarg));
555 return FAIL;
556 }
557 }
558 return OK;
559 }
560
561 static int
562 json_decode_string(js_read_T *reader, typval_T *res) 381 json_decode_string(js_read_T *reader, typval_T *res)
563 { 382 {
564 garray_T ga; 383 garray_T ga;
565 int len; 384 int len;
566 char_u *p; 385 char_u *p;
721 ga_clear(&ga); 540 ga_clear(&ga);
722 } 541 }
723 return MAYBE; 542 return MAYBE;
724 } 543 }
725 544
545 typedef enum {
546 JSON_ARRAY, /* parsing items in an array */
547 JSON_OBJECT_KEY, /* parsing key of an object */
548 JSON_OBJECT /* parsing item in an object, after the key */
549 } json_decode_T;
550
551 typedef struct {
552 json_decode_T jd_type;
553 typval_T jd_tv; /* the list or dict */
554 typval_T jd_key_tv;
555 char_u *jd_key;
556 } json_dec_item_T;
557
726 /* 558 /*
727 * Decode one item and put it in "res". If "res" is NULL only advance. 559 * Decode one item and put it in "res". If "res" is NULL only advance.
728 * Must already have skipped white space. 560 * Must already have skipped white space.
729 * 561 *
730 * Return FAIL for a decoding error (and give an error). 562 * Return FAIL for a decoding error (and give an error).
733 static int 565 static int
734 json_decode_item(js_read_T *reader, typval_T *res, int options) 566 json_decode_item(js_read_T *reader, typval_T *res, int options)
735 { 567 {
736 char_u *p; 568 char_u *p;
737 int len; 569 int len;
570 int retval;
571 garray_T stack;
572 typval_T item;
573 typval_T *cur_item;
574 json_dec_item_T *top_item;
575 char_u key_buf[NUMBUFLEN];
576
577 ga_init2(&stack, sizeof(json_dec_item_T), 100);
578 cur_item = res;
579 init_tv(&item);
738 580
739 fill_numbuflen(reader); 581 fill_numbuflen(reader);
740 p = reader->js_buf + reader->js_used; 582 p = reader->js_buf + reader->js_used;
741 switch (*p) 583 for (;;)
742 { 584 {
743 case '[': /* array */ 585 top_item = NULL;
744 return json_decode_array(reader, res, options); 586 if (stack.ga_len > 0)
745 587 {
746 case '{': /* object */ 588 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
747 return json_decode_object(reader, res, options); 589 json_skip_white(reader);
748 590 p = reader->js_buf + reader->js_used;
749 case '"': /* string */ 591 if (*p == NUL)
750 return json_decode_string(reader, res); 592 {
751 593 retval = MAYBE;
752 case ',': /* comma: empty item */ 594 if (top_item->jd_type == JSON_OBJECT)
753 if ((options & JSON_JS) == 0) 595 /* did get the key, clear it */
754 { 596 clear_tv(&top_item->jd_key_tv);
755 EMSG(_(e_invarg)); 597 goto theend;
756 return FAIL; 598 }
757 } 599 if (top_item->jd_type == JSON_OBJECT_KEY
758 /* FALLTHROUGH */ 600 || top_item->jd_type == JSON_ARRAY)
759 case NUL: /* empty */ 601 {
760 if (res != NULL) 602 /* Check for end of object or array. */
761 { 603 if (*p == (top_item->jd_type == JSON_ARRAY ? ']' : '}'))
762 res->v_type = VAR_SPECIAL; 604 {
763 res->vval.v_number = VVAL_NONE; 605 ++reader->js_used; /* consume the ']' or '}' */
764 } 606 --stack.ga_len;
765 return OK; 607 if (stack.ga_len == 0)
766 608 {
767 default: 609 retval = OK;
768 if (VIM_ISDIGIT(*p) || *p == '-') 610 goto theend;
769 { 611 }
612 if (cur_item != NULL)
613 cur_item = &top_item->jd_tv;
614 goto item_end;
615 }
616 }
617 }
618
619 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
620 && (options & JSON_JS)
621 && reader->js_buf[reader->js_used] != '"')
622 {
623 char_u *key;
624
625 /* accept an object key that is not in quotes */
626 key = p = reader->js_buf + reader->js_used;
627 while (*p != NUL && *p != ':' && *p > ' ')
628 ++p;
629 cur_item->v_type = VAR_STRING;
630 cur_item->vval.v_string = vim_strnsave(key, (int)(p - key));
631 reader->js_used += (int)(p - key);
632 top_item->jd_key = cur_item->vval.v_string;
633 }
634 else
635 {
636 switch (*p)
637 {
638 case '[': /* start of array */
639 if (ga_grow(&stack, 1) == FAIL)
640 {
641 retval = FAIL;
642 break;
643 }
644 if (cur_item != NULL && rettv_list_alloc(cur_item) == FAIL)
645 {
646 cur_item->v_type = VAR_SPECIAL;
647 cur_item->vval.v_number = VVAL_NONE;
648 retval = FAIL;
649 break;
650 }
651
652 ++reader->js_used; /* consume the '[' */
653 top_item = ((json_dec_item_T *)stack.ga_data)
654 + stack.ga_len;
655 top_item->jd_type = JSON_ARRAY;
656 ++stack.ga_len;
657 if (cur_item != NULL)
658 {
659 top_item->jd_tv = *cur_item;
660 cur_item = &item;
661 }
662 continue;
663
664 case '{': /* start of object */
665 if (ga_grow(&stack, 1) == FAIL)
666 {
667 retval = FAIL;
668 break;
669 }
670 if (cur_item != NULL && rettv_dict_alloc(cur_item) == FAIL)
671 {
672 cur_item->v_type = VAR_SPECIAL;
673 cur_item->vval.v_number = VVAL_NONE;
674 retval = FAIL;
675 break;
676 }
677
678 ++reader->js_used; /* consume the '{' */
679 top_item = ((json_dec_item_T *)stack.ga_data)
680 + stack.ga_len;
681 top_item->jd_type = JSON_OBJECT_KEY;
682 ++stack.ga_len;
683 if (cur_item != NULL)
684 {
685 top_item->jd_tv = *cur_item;
686 cur_item = &top_item->jd_key_tv;
687 }
688 continue;
689
690 case '"': /* string */
691 retval = json_decode_string(reader, cur_item);
692 break;
693
694 case ',': /* comma: empty item */
695 if ((options & JSON_JS) == 0)
696 {
697 EMSG(_(e_invarg));
698 retval = FAIL;
699 break;
700 }
701 /* FALLTHROUGH */
702 case NUL: /* empty */
703 if (cur_item != NULL)
704 {
705 cur_item->v_type = VAR_SPECIAL;
706 cur_item->vval.v_number = VVAL_NONE;
707 }
708 retval = OK;
709 break;
710
711 default:
712 if (VIM_ISDIGIT(*p) || *p == '-')
713 {
770 #ifdef FEAT_FLOAT 714 #ifdef FEAT_FLOAT
771 char_u *sp = p; 715 char_u *sp = p;
772 716
773 if (*sp == '-') 717 if (*sp == '-')
774 { 718 {
775 ++sp; 719 ++sp;
776 if (*sp == NUL) 720 if (*sp == NUL)
777 return MAYBE; 721 {
778 if (!VIM_ISDIGIT(*sp)) 722 retval = MAYBE;
723 break;
724 }
725 if (!VIM_ISDIGIT(*sp))
726 {
727 EMSG(_(e_invarg));
728 retval = FAIL;
729 break;
730 }
731 }
732 sp = skipdigits(sp);
733 if (*sp == '.' || *sp == 'e' || *sp == 'E')
734 {
735 if (cur_item == NULL)
736 {
737 float_T f;
738
739 len = string2float(p, &f);
740 }
741 else
742 {
743 cur_item->v_type = VAR_FLOAT;
744 len = string2float(p, &cur_item->vval.v_float);
745 }
746 }
747 else
748 #endif
749 {
750 varnumber_T nr;
751
752 vim_str2nr(reader->js_buf + reader->js_used,
753 NULL, &len, 0, /* what */
754 &nr, NULL, 0);
755 if (cur_item != NULL)
756 {
757 cur_item->v_type = VAR_NUMBER;
758 cur_item->vval.v_number = nr;
759 }
760 }
761 reader->js_used += len;
762 retval = OK;
763 break;
764 }
765 if (STRNICMP((char *)p, "false", 5) == 0)
766 {
767 reader->js_used += 5;
768 if (cur_item != NULL)
769 {
770 cur_item->v_type = VAR_SPECIAL;
771 cur_item->vval.v_number = VVAL_FALSE;
772 }
773 retval = OK;
774 break;
775 }
776 if (STRNICMP((char *)p, "true", 4) == 0)
777 {
778 reader->js_used += 4;
779 if (cur_item != NULL)
780 {
781 cur_item->v_type = VAR_SPECIAL;
782 cur_item->vval.v_number = VVAL_TRUE;
783 }
784 retval = OK;
785 break;
786 }
787 if (STRNICMP((char *)p, "null", 4) == 0)
788 {
789 reader->js_used += 4;
790 if (cur_item != NULL)
791 {
792 cur_item->v_type = VAR_SPECIAL;
793 cur_item->vval.v_number = VVAL_NULL;
794 }
795 retval = OK;
796 break;
797 }
798 #ifdef FEAT_FLOAT
799 if (STRNICMP((char *)p, "NaN", 3) == 0)
800 {
801 reader->js_used += 3;
802 if (cur_item != NULL)
803 {
804 cur_item->v_type = VAR_FLOAT;
805 cur_item->vval.v_float = NAN;
806 }
807 retval = OK;
808 break;
809 }
810 if (STRNICMP((char *)p, "Infinity", 8) == 0)
811 {
812 reader->js_used += 8;
813 if (cur_item != NULL)
814 {
815 cur_item->v_type = VAR_FLOAT;
816 cur_item->vval.v_float = INFINITY;
817 }
818 retval = OK;
819 break;
820 }
821 #endif
822 /* check for truncated name */
823 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
824 if (
825 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
826 #ifdef FEAT_FLOAT
827 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
828 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
829 #endif
830 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
831 || STRNICMP((char *)p, "null", len) == 0)))
832
833 retval = MAYBE;
834 else
835 retval = FAIL;
836 break;
837 }
838
839 /* We are finished when retval is FAIL or MAYBE and when at the
840 * toplevel. */
841 if (retval == FAIL)
842 break;
843 if (retval == MAYBE || stack.ga_len == 0)
844 goto theend;
845
846 if (top_item != NULL && top_item->jd_type == JSON_OBJECT_KEY
847 && cur_item != NULL)
848 {
849 top_item->jd_key = get_tv_string_buf_chk(cur_item, key_buf);
850 if (top_item->jd_key == NULL || *top_item->jd_key == NUL)
851 {
852 clear_tv(cur_item);
853 EMSG(_(e_invarg));
854 retval = FAIL;
855 goto theend;
856 }
857 }
858 }
859
860 item_end:
861 top_item = ((json_dec_item_T *)stack.ga_data) + stack.ga_len - 1;
862 switch (top_item->jd_type)
863 {
864 case JSON_ARRAY:
865 if (res != NULL)
866 {
867 listitem_T *li = listitem_alloc();
868
869 if (li == NULL)
870 {
871 clear_tv(cur_item);
872 retval = FAIL;
873 goto theend;
874 }
875 li->li_tv = *cur_item;
876 list_append(top_item->jd_tv.vval.v_list, li);
877 }
878 if (cur_item != NULL)
879 cur_item = &item;
880
881 json_skip_white(reader);
882 p = reader->js_buf + reader->js_used;
883 if (*p == ',')
884 ++reader->js_used;
885 else if (*p != ']')
886 {
887 if (*p == NUL)
888 retval = MAYBE;
889 else
779 { 890 {
780 EMSG(_(e_invarg)); 891 EMSG(_(e_invarg));
781 return FAIL; 892 retval = FAIL;
782 } 893 }
783 } 894 goto theend;
784 sp = skipdigits(sp); 895 }
785 if (*sp == '.' || *sp == 'e' || *sp == 'E') 896 break;
786 { 897
787 if (res == NULL) 898 case JSON_OBJECT_KEY:
788 { 899 json_skip_white(reader);
789 float_T f; 900 p = reader->js_buf + reader->js_used;
790 901 if (*p != ':')
791 len = string2float(p, &f); 902 {
792 } 903 if (cur_item != NULL)
904 clear_tv(cur_item);
905 if (*p == NUL)
906 retval = MAYBE;
793 else 907 else
794 { 908 {
795 res->v_type = VAR_FLOAT; 909 EMSG(_(e_invarg));
796 len = string2float(p, &res->vval.v_float); 910 retval = FAIL;
797 } 911 }
798 } 912 goto theend;
799 else 913 }
800 #endif 914 ++reader->js_used;
801 { 915 json_skip_white(reader);
802 varnumber_T nr; 916 top_item->jd_type = JSON_OBJECT;
803 917 if (cur_item != NULL)
804 vim_str2nr(reader->js_buf + reader->js_used, 918 cur_item = &item;
805 NULL, &len, 0, /* what */ 919 break;
806 &nr, NULL, 0); 920
807 if (res != NULL) 921 case JSON_OBJECT:
808 { 922 if (cur_item != NULL
809 res->v_type = VAR_NUMBER; 923 && dict_find(top_item->jd_tv.vval.v_dict,
810 res->vval.v_number = nr; 924 top_item->jd_key, -1) != NULL)
811 } 925 {
812 } 926 EMSG2(_("E937: Duplicate key in JSON: \"%s\""),
813 reader->js_used += len; 927 top_item->jd_key);
814 return OK; 928 clear_tv(&top_item->jd_key_tv);
815 } 929 clear_tv(cur_item);
816 if (STRNICMP((char *)p, "false", 5) == 0) 930 retval = FAIL;
817 { 931 goto theend;
818 reader->js_used += 5; 932 }
819 if (res != NULL) 933
820 { 934 if (cur_item != NULL)
821 res->v_type = VAR_SPECIAL; 935 {
822 res->vval.v_number = VVAL_FALSE; 936 dictitem_T *di = dictitem_alloc(top_item->jd_key);
823 } 937
824 return OK; 938 clear_tv(&top_item->jd_key_tv);
825 } 939 if (di == NULL)
826 if (STRNICMP((char *)p, "true", 4) == 0) 940 {
827 { 941 clear_tv(cur_item);
828 reader->js_used += 4; 942 retval = FAIL;
829 if (res != NULL) 943 goto theend;
830 { 944 }
831 res->v_type = VAR_SPECIAL; 945 di->di_tv = *cur_item;
832 res->vval.v_number = VVAL_TRUE; 946 di->di_tv.v_lock = 0;
833 } 947 if (dict_add(top_item->jd_tv.vval.v_dict, di) == FAIL)
834 return OK; 948 {
835 } 949 dictitem_free(di);
836 if (STRNICMP((char *)p, "null", 4) == 0) 950 retval = FAIL;
837 { 951 goto theend;
838 reader->js_used += 4; 952 }
839 if (res != NULL) 953 }
840 { 954
841 res->v_type = VAR_SPECIAL; 955 json_skip_white(reader);
842 res->vval.v_number = VVAL_NULL; 956 p = reader->js_buf + reader->js_used;
843 } 957 if (*p == ',')
844 return OK; 958 ++reader->js_used;
845 } 959 else if (*p != '}')
846 #ifdef FEAT_FLOAT 960 {
847 if (STRNICMP((char *)p, "NaN", 3) == 0) 961 if (*p == NUL)
848 { 962 retval = MAYBE;
849 reader->js_used += 3; 963 else
850 if (res != NULL) 964 {
851 { 965 EMSG(_(e_invarg));
852 res->v_type = VAR_FLOAT; 966 retval = FAIL;
853 res->vval.v_float = NAN; 967 }
854 } 968 goto theend;
855 return OK; 969 }
856 } 970 top_item->jd_type = JSON_OBJECT_KEY;
857 if (STRNICMP((char *)p, "Infinity", 8) == 0) 971 if (cur_item != NULL)
858 { 972 cur_item = &top_item->jd_key_tv;
859 reader->js_used += 8; 973 break;
860 if (res != NULL) 974 }
861 { 975 }
862 res->v_type = VAR_FLOAT; 976
863 res->vval.v_float = INFINITY; 977 /* Get here when parsing failed. */
864 }
865 return OK;
866 }
867 #endif
868 /* check for truncated name */
869 len = (int)(reader->js_end - (reader->js_buf + reader->js_used));
870 if (
871 (len < 5 && STRNICMP((char *)p, "false", len) == 0)
872 #ifdef FEAT_FLOAT
873 || (len < 8 && STRNICMP((char *)p, "Infinity", len) == 0)
874 || (len < 3 && STRNICMP((char *)p, "NaN", len) == 0)
875 #endif
876 || (len < 4 && (STRNICMP((char *)p, "true", len) == 0
877 || STRNICMP((char *)p, "null", len) == 0)))
878 return MAYBE;
879 break;
880 }
881
882 if (res != NULL) 978 if (res != NULL)
883 { 979 {
980 clear_tv(res);
884 res->v_type = VAR_SPECIAL; 981 res->v_type = VAR_SPECIAL;
885 res->vval.v_number = VVAL_NONE; 982 res->vval.v_number = VVAL_NONE;
886 } 983 }
887 EMSG(_(e_invarg)); 984 EMSG(_(e_invarg));
888 return FAIL; 985
986 theend:
987 ga_clear(&stack);
988 clear_tv(&item);
989 return retval;
889 } 990 }
890 991
891 /* 992 /*
892 * Decode the JSON from "reader" and store the result in "res". 993 * Decode the JSON from "reader" and store the result in "res".
893 * "options" can be JSON_JS or zero; 994 * "options" can be JSON_JS or zero;