Skip to content

Commit 55fab43

Browse files
committed
patch 7.4.1278
Problem: When jsonencode() fails it still returns something. Solution: Return an empty string on failure.
1 parent a6f72ba commit 55fab43

6 files changed

Lines changed: 47 additions & 12 deletions

File tree

src/channel.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -853,24 +853,31 @@ channel_exe_cmd(int idx, char_u *cmd, typval_T *arg2, typval_T *arg3)
853853
{
854854
typval_T *tv;
855855
typval_T err_tv;
856-
char_u *json;
856+
char_u *json = NULL;
857857

858858
/* Don't pollute the display with errors. */
859859
++emsg_skip;
860860
tv = eval_expr(arg, NULL);
861-
--emsg_skip;
862861
if (is_eval)
863862
{
864-
if (tv == NULL)
863+
if (tv != NULL)
864+
json = json_encode_nr_expr(arg3->vval.v_number, tv);
865+
if (tv == NULL || (json != NULL && *json == NUL))
865866
{
867+
/* If evaluation failed or the result can't be encoded
868+
* then return the string "ERROR". */
866869
err_tv.v_type = VAR_STRING;
867870
err_tv.vval.v_string = (char_u *)"ERROR";
868871
tv = &err_tv;
872+
json = json_encode_nr_expr(arg3->vval.v_number, tv);
873+
}
874+
if (json != NULL)
875+
{
876+
channel_send(idx, json, "eval");
877+
vim_free(json);
869878
}
870-
json = json_encode_nr_expr(arg3->vval.v_number, tv);
871-
channel_send(idx, json, "eval");
872-
vim_free(json);
873879
}
880+
--emsg_skip;
874881
if (tv != &err_tv)
875882
free_tv(tv);
876883
}

src/json.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ static int json_decode_item(js_read_T *reader, typval_T *res);
2121

2222
/*
2323
* Encode "val" into a JSON format string.
24+
* The result is in allocated memory.
25+
* The result is empty when encoding fails.
2426
*/
2527
char_u *
2628
json_encode(typval_T *val)
@@ -29,12 +31,16 @@ json_encode(typval_T *val)
2931

3032
/* Store bytes in the growarray. */
3133
ga_init2(&ga, 1, 4000);
32-
json_encode_item(&ga, val, get_copyID(), TRUE);
34+
if (json_encode_item(&ga, val, get_copyID(), TRUE) == FAIL)
35+
{
36+
vim_free(ga.ga_data);
37+
return vim_strsave((char_u *)"");
38+
}
3339
return ga.ga_data;
3440
}
3541

3642
/*
37-
* Encode ["nr", "val"] into a JSON format string.
43+
* Encode ["nr", "val"] into a JSON format string in allocated memory.
3844
* Returns NULL when out of memory.
3945
*/
4046
char_u *
@@ -136,8 +142,11 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
136142
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
137143
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
138144
case VVAL_NONE: if (!allow_none)
145+
{
139146
/* TODO: better error */
140147
EMSG(_(e_invarg));
148+
return FAIL;
149+
}
141150
break;
142151
case VVAL_NULL: ga_concat(gap, (char_u *)"null"); break;
143152
}
@@ -155,6 +164,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
155164
break;
156165

157166
case VAR_FUNC:
167+
case VAR_JOB:
158168
/* no JSON equivalent TODO: better error */
159169
EMSG(_(e_invarg));
160170
return FAIL;
@@ -226,14 +236,15 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID, int allow_none)
226236
}
227237
break;
228238

229-
#ifdef FEAT_FLOAT
230239
case VAR_FLOAT:
240+
#ifdef FEAT_FLOAT
231241
vim_snprintf((char *)numbuf, NUMBUFLEN, "%g", val->vval.v_float);
232242
ga_concat(gap, numbuf);
233243
break;
234244
#endif
235-
default: EMSG2(_(e_intern2), "json_encode_item()"); break;
236-
return FAIL;
245+
case VAR_UNKNOWN:
246+
EMSG2(_(e_intern2), "json_encode_item()"); break;
247+
return FAIL;
237248
}
238249
return OK;
239250
}

src/testdir/test_channel.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ def handle(self):
9393
print("sending: {}".format(cmd))
9494
self.request.sendall(cmd.encode('utf-8'))
9595
response = "ok"
96+
elif decoded[1] == 'eval-error':
97+
# Send an eval request that works but the result can't
98+
# be encoded.
99+
cmd = '["eval","function(\\"tr\\")", -3]'
100+
print("sending: {}".format(cmd))
101+
self.request.sendall(cmd.encode('utf-8'))
102+
response = "ok"
96103
elif decoded[1] == 'eval-bad':
97104
# Send an eval request missing the third argument.
98105
cmd = '["eval","xxx"]'

src/testdir/test_channel.vim

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,15 @@ func Test_communicate()
118118
sleep 10m
119119
call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
120120

121+
" Send an eval request that works but can't be encoded.
122+
call assert_equal('ok', ch_sendexpr(handle, 'eval-error'))
123+
sleep 10m
124+
call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
125+
121126
" Send a bad eval request. There will be no response.
122127
call assert_equal('ok', ch_sendexpr(handle, 'eval-bad'))
123128
sleep 10m
124-
call assert_equal([-2, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
129+
call assert_equal([-3, 'ERROR'], ch_sendexpr(handle, 'eval-result'))
125130

126131
" Send an expr request
127132
call assert_equal('ok', ch_sendexpr(handle, 'an expr'))

src/testdir/test_json.vim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ func Test_encode()
7575
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
7676
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
7777
call assert_fails('echo jsonencode({"key":v:none})', 'E474:')
78+
79+
silent! let res = jsonencode(function("tr"))
80+
call assert_equal("", res)
7881
endfunc
7982

8083
func Test_decode()

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,8 @@ static char *(features[]) =
747747

748748
static int included_patches[] =
749749
{ /* Add new patch number below this line */
750+
/**/
751+
1278,
750752
/**/
751753
1277,
752754
/**/

0 commit comments

Comments
 (0)