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
index f409e1d..f522e80 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -1896,9 +1896,12 @@
 
     /* 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
index f66fa9a..74676c2 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6818,8 +6818,7 @@
     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
index 4ec4411..2d0e706 100644
--- a/src/json.c
+++ b/src/json.c
@@ -428,6 +428,7 @@
 	{
 	    if (*p == NUL)
 		return MAYBE;
+	    EMSG(_(e_invarg));
 	    return FAIL;
 	}
     }
@@ -488,6 +489,7 @@
 		if (key == NULL || *key == NUL)
 		{
 		    clear_tv(&tvkey);
+		    EMSG(_(e_invarg));
 		    return FAIL;
 		}
 	    }
@@ -501,6 +503,7 @@
 		clear_tv(&tvkey);
 	    if (*p == NUL)
 		return MAYBE;
+	    EMSG(_(e_invarg));
 	    return FAIL;
 	}
 	++reader->js_used;
@@ -514,6 +517,14 @@
 	    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 @@
 	{
 	    if (*p == NUL)
 		return MAYBE;
+	    EMSG(_(e_invarg));
 	    return FAIL;
 	}
     }
@@ -715,7 +727,7 @@
  * 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 @@
 
 	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 @@
 		    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 @@
 	res->v_type = VAR_SPECIAL;
 	res->vval.v_number = VVAL_NONE;
     }
+    EMSG(_(e_invarg));
     return FAIL;
 }
 
@@ -884,10 +903,17 @@
     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
index e149036..ecca038 100644
--- a/src/testdir/test_json.vim
+++ b/src/testdir/test_json.vim
@@ -148,8 +148,9 @@
 
   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:")
diff --git a/src/version.c b/src/version.c
index b5039a0..f5327cc 100644
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    166,
+/**/
     165,
 /**/
     164,