# HG changeset patch # User Christian Brabandt # Date 1484058605 -3600 # Node ID f83b6a0b6148b6ac7e9ebc9f7c6301927ece7300 # Parent fb7cdd106c9bd54666827b929bd6c61ad4786506 patch 8.0.0166: JSON with a duplicate key gives an internal error commit https://github.com/vim/vim/commit/03c60c1573cdbebbb662863cfc1780d19d511db5 Author: Bram Moolenaar Date: Tue Jan 10 15:15:37 2017 +0100 patch 8.0.0166: JSON with a duplicate key gives an internal error Problem: JSON with a duplicate key gives an internal error. (Lcd) Solution: Give a normal error. Avoid an error when parsing JSON from a remote client fails. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -1896,9 +1896,12 @@ channel_parse_json(channel_T *channel, c /* When a message is incomplete we wait for a short while for more to * arrive. After the delay drop the input, otherwise a truncated string - * or list will make us hang. */ + * or list will make us hang. + * Do not generate error messages, they will be written in a channel log. */ + ++emsg_silent; status = json_decode(&reader, &listtv, chanpart->ch_mode == MODE_JS ? JSON_JS : 0); + --emsg_silent; if (status == OK) { /* Only accept the response when it is a list with at least two diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6818,8 +6818,7 @@ f_json_decode(typval_T *argvars, typval_ reader.js_buf = get_tv_string(&argvars[0]); reader.js_fill = NULL; reader.js_used = 0; - if (json_decode_all(&reader, rettv, 0) != OK) - EMSG(_(e_invarg)); + json_decode_all(&reader, rettv, 0); } /* diff --git a/src/json.c b/src/json.c --- a/src/json.c +++ b/src/json.c @@ -428,6 +428,7 @@ json_decode_array(js_read_T *reader, typ { if (*p == NUL) return MAYBE; + EMSG(_(e_invarg)); return FAIL; } } @@ -488,6 +489,7 @@ json_decode_object(js_read_T *reader, ty if (key == NULL || *key == NUL) { clear_tv(&tvkey); + EMSG(_(e_invarg)); return FAIL; } } @@ -501,6 +503,7 @@ json_decode_object(js_read_T *reader, ty clear_tv(&tvkey); if (*p == NUL) return MAYBE; + EMSG(_(e_invarg)); return FAIL; } ++reader->js_used; @@ -514,6 +517,14 @@ json_decode_object(js_read_T *reader, ty return ret; } + if (res != NULL && dict_find(res->vval.v_dict, key, -1) != NULL) + { + EMSG2(_("E937: Duplicate key in JSON: \"%s\""), key); + clear_tv(&tvkey); + clear_tv(&item); + return FAIL; + } + if (res != NULL) { di = dictitem_alloc(key); @@ -540,6 +551,7 @@ json_decode_object(js_read_T *reader, ty { if (*p == NUL) return MAYBE; + EMSG(_(e_invarg)); return FAIL; } } @@ -715,7 +727,7 @@ json_decode_string(js_read_T *reader, ty * Decode one item and put it in "res". If "res" is NULL only advance. * Must already have skipped white space. * - * Return FAIL for a decoding error. + * Return FAIL for a decoding error (and give an error). * Return MAYBE for an incomplete message. */ static int @@ -739,7 +751,10 @@ json_decode_item(js_read_T *reader, typv case ',': /* comma: empty item */ if ((options & JSON_JS) == 0) + { + EMSG(_(e_invarg)); return FAIL; + } /* FALLTHROUGH */ case NUL: /* empty */ if (res != NULL) @@ -761,7 +776,10 @@ json_decode_item(js_read_T *reader, typv if (*sp == NUL) return MAYBE; if (!VIM_ISDIGIT(*sp)) + { + EMSG(_(e_invarg)); return FAIL; + } } sp = skipdigits(sp); if (*sp == '.' || *sp == 'e' || *sp == 'E') @@ -866,6 +884,7 @@ json_decode_item(js_read_T *reader, typv res->v_type = VAR_SPECIAL; res->vval.v_number = VVAL_NONE; } + EMSG(_(e_invarg)); return FAIL; } @@ -884,10 +903,17 @@ json_decode_all(js_read_T *reader, typva json_skip_white(reader); ret = json_decode_item(reader, res, options); if (ret != OK) + { + if (ret == MAYBE) + EMSG(_(e_invarg)); return FAIL; + } json_skip_white(reader); if (reader->js_buf[reader->js_used] != NUL) + { + EMSG(_(e_trailing)); return FAIL; + } return OK; } diff --git a/src/testdir/test_json.vim b/src/testdir/test_json.vim --- a/src/testdir/test_json.vim +++ b/src/testdir/test_json.vim @@ -148,8 +148,9 @@ func Test_json_decode() call assert_fails('call json_decode("\"")', "E474:") call assert_fails('call json_decode("blah")', "E474:") - call assert_fails('call json_decode("true blah")', "E474:") + call assert_fails('call json_decode("true blah")', "E488:") call assert_fails('call json_decode("")', "E474:") + call assert_fails('call json_decode("{\"a\":1,\"a\":2}")', "E937:") call assert_fails('call json_decode("{")', "E474:") call assert_fails('call json_decode("{foobar}")', "E474:") diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -765,6 +765,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 166, +/**/ 165, /**/ 164,