changeset 7965:646d5148fee2 v7.4.1278

commit https://github.com/vim/vim/commit/55fab439a6f3bba6dbe780ac034b84d5822a1a96 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Feb 7 16:53:13 2016 +0100 patch 7.4.1278 Problem: When jsonencode() fails it still returns something. Solution: Return an empty string on failure.
author Christian Brabandt <cb@256bit.org>
date Sun, 07 Feb 2016 17:00:05 +0100
parents 78b678f510f4
children 79c5a86fcdfe
files src/channel.c src/json.c src/testdir/test_channel.py src/testdir/test_channel.vim src/testdir/test_json.vim src/version.c
diffstat 6 files changed, 47 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -853,24 +853,31 @@ channel_exe_cmd(int idx, char_u *cmd, ty
 	{
 	    typval_T	*tv;
 	    typval_T	err_tv;
-	    char_u	*json;
+	    char_u	*json = NULL;
 
 	    /* Don't pollute the display with errors. */
 	    ++emsg_skip;
 	    tv = eval_expr(arg, NULL);
-	    --emsg_skip;
 	    if (is_eval)
 	    {
-		if (tv == NULL)
+		if (tv != NULL)
+		    json = json_encode_nr_expr(arg3->vval.v_number, tv);
+		if (tv == NULL || (json != NULL && *json == NUL))
 		{
+		    /* If evaluation failed or the result can't be encoded
+		     * then return the string "ERROR". */
 		    err_tv.v_type = VAR_STRING;
 		    err_tv.vval.v_string = (char_u *)"ERROR";
 		    tv = &err_tv;
+		    json = json_encode_nr_expr(arg3->vval.v_number, tv);
 		}
-		json = json_encode_nr_expr(arg3->vval.v_number, tv);
-		channel_send(idx, json, "eval");
-		vim_free(json);
+		if (json != NULL)
+		{
+		    channel_send(idx, json, "eval");
+		    vim_free(json);
+		}
 	    }
+	    --emsg_skip;
 	    if (tv != &err_tv)
 		free_tv(tv);
 	}
--- a/src/json.c
+++ b/src/json.c
@@ -21,6 +21,8 @@ static int json_decode_item(js_read_T *r
 
 /*
  * Encode "val" into a JSON format string.
+ * The result is in allocated memory.
+ * The result is empty when encoding fails.
  */
     char_u *
 json_encode(typval_T *val)
@@ -29,12 +31,16 @@ json_encode(typval_T *val)
 
     /* Store bytes in the growarray. */
     ga_init2(&ga, 1, 4000);
-    json_encode_item(&ga, val, get_copyID(), TRUE);
+    if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL)
+    {
+	vim_free(ga.ga_data);
+	return vim_strsave((char_u *)"");
+    }
     return ga.ga_data;
 }
 
 /*
- * Encode ["nr", "val"] into a JSON format string.
+ * Encode ["nr", "val"] into a JSON format string in allocated memory.
  * Returns NULL when out of memory.
  */
     char_u *
@@ -136,8 +142,11 @@ json_encode_item(garray_T *gap, typval_T
 		case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
 		case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
 		case VVAL_NONE: if (!allow_none)
+				{
 				    /* TODO: better error */
 				    EMSG(_(e_invarg));
+				    return FAIL;
+				}
 				break;
 		case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
 	    }
@@ -155,6 +164,7 @@ json_encode_item(garray_T *gap, typval_T
 	    break;
 
 	case VAR_FUNC:
+	case VAR_JOB:
 	    /* no JSON equivalent TODO: better error */
 	    EMSG(_(e_invarg));
 	    return FAIL;
@@ -226,14 +236,15 @@ json_encode_item(garray_T *gap, typval_T
 	    }
 	    break;
 
+	case VAR_FLOAT:
 #ifdef FEAT_FLOAT
-	case VAR_FLOAT:
 	    vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
 	    ga_concat(gap, numbuf);
 	    break;
 #endif
-	default: EMSG2(_(e_intern2), "json_encode_item()"); break;
-		 return FAIL;
+	case VAR_UNKNOWN:
+	    EMSG2(_(e_intern2), "json_encode_item()"); break;
+	    return FAIL;
     }
     return OK;
 }
--- a/src/testdir/test_channel.py
+++ b/src/testdir/test_channel.py
@@ -93,6 +93,13 @@ class ThreadedTCPRequestHandler(socketse
                         print("sending: {}".format(cmd))
                         self.request.sendall(cmd.encode('utf-8'))
                         response = "ok"
+                    elif decoded[1] == 'eval-error':
+                        # Send an eval request that works but the result can't
+                        # be encoded.
+                        cmd = '["eval","function(\\"tr\\")", -3]'
+                        print("sending: {}".format(cmd))
+                        self.request.sendall(cmd.encode('utf-8'))
+                        response = "ok"
                     elif decoded[1] == 'eval-bad':
                         # Send an eval request missing the third argument.
                         cmd = '["eval","xxx"]'
--- a/src/testdir/test_channel.vim
+++ b/src/testdir/test_channel.vim
@@ -118,10 +118,15 @@ func Test_communicate()
   sleep 10m
   call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
 
+  " Send an eval request that works but can't be encoded.
+  call assert_equal('ok', ch_sendexpr(handle, 'eval-error'))
+  sleep 10m
+  call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
+
   " Send a bad eval request. There will be no response.
   call assert_equal('ok', ch_sendexpr(handle, 'eval-bad'))
   sleep 10m
-  call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
+  call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
 
   " Send an expr request
   call assert_equal('ok', ch_sendexpr(handle, 'an expr'))
--- a/src/testdir/test_json.vim
+++ b/src/testdir/test_json.vim
@@ -75,6 +75,9 @@ func Test_encode()
   call assert_fails('echo jsonencode(function("tr"))', 'E474:')
   call assert_fails('echo jsonencode([function("tr")])', 'E474:')
   call assert_fails('echo jsonencode({"key":v:none})', 'E474:')
+
+  silent! let res = jsonencode(function("tr"))
+  call assert_equal("", res)
 endfunc
 
 func Test_decode()
--- a/src/version.c
+++ b/src/version.c
@@ -748,6 +748,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1278,
+/**/
     1277,
 /**/
     1276,