changeset 10553:f83b6a0b6148 v8.0.0166

patch 8.0.0166: JSON with a duplicate key gives an internal error commit https://github.com/vim/vim/commit/03c60c1573cdbebbb662863cfc1780d19d511db5 Author: Bram Moolenaar <Bram@vim.org> 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.
author Christian Brabandt <cb@256bit.org>
date Tue, 10 Jan 2017 15:30:05 +0100
parents fb7cdd106c9b
children 9dc3c9de4198
files src/channel.c src/evalfunc.c src/json.c src/testdir/test_json.vim src/version.c
diffstat 5 files changed, 36 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- 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
--- 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);
 }
 
 /*
--- 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;
 }
 
--- 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("<foobar>")', "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:")
--- 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,