Skip to content

Commit fcaaae6

Browse files
committed
patch 7.4.1166
Problem: Can't encode a Funcref into JSON. jsonencode() doesn't handle the same list or dict twice properly. (Nikolay Pavlov) Solution: Give an error. Reset copyID when the list or dict is finished.
1 parent 938ee83 commit fcaaae6

4 files changed

Lines changed: 34 additions & 8 deletions

File tree

src/json.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "vim.h"
1717

1818
#if defined(FEAT_EVAL) || defined(PROTO)
19+
static int json_encode_item(garray_T *gap, typval_T *val, int copyID);
1920
static void json_decode_item(js_read_T *reader, typval_T *res);
2021

2122
/*
@@ -83,7 +84,11 @@ write_string(garray_T *gap, char_u *str)
8384
}
8485
}
8586

86-
void
87+
/*
88+
* Encode "val" into "gap".
89+
* Return FAIL or OK.
90+
*/
91+
static int
8792
json_encode_item(garray_T *gap, typval_T *val, int copyID)
8893
{
8994
char_u numbuf[NUMBUFLEN];
@@ -94,7 +99,7 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
9499
switch (val->v_type)
95100
{
96101
case VAR_SPECIAL:
97-
switch(val->vval.v_number)
102+
switch (val->vval.v_number)
98103
{
99104
case VVAL_FALSE: ga_concat(gap, (char_u *)"false"); break;
100105
case VVAL_TRUE: ga_concat(gap, (char_u *)"true"); break;
@@ -115,8 +120,9 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
115120
break;
116121

117122
case VAR_FUNC:
118-
/* no JSON equivalent, skip */
119-
break;
123+
/* no JSON equivalent */
124+
EMSG(_(e_invarg));
125+
return FAIL;
120126

121127
case VAR_LIST:
122128
l = val->vval.v_list;
@@ -134,12 +140,14 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
134140
ga_append(gap, '[');
135141
for (li = l->lv_first; li != NULL && !got_int; )
136142
{
137-
json_encode_item(gap, &li->li_tv, copyID);
143+
if (json_encode_item(gap, &li->li_tv, copyID) == FAIL)
144+
return FAIL;
138145
li = li->li_next;
139146
if (li != NULL)
140147
ga_append(gap, ',');
141148
}
142149
ga_append(gap, ']');
150+
l->lv_copyID = 0;
143151
}
144152
}
145153
break;
@@ -172,10 +180,12 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
172180
ga_append(gap, ',');
173181
write_string(gap, hi->hi_key);
174182
ga_append(gap, ':');
175-
json_encode_item(gap, &dict_lookup(hi)->di_tv,
176-
copyID);
183+
if (json_encode_item(gap, &dict_lookup(hi)->di_tv,
184+
copyID) == FAIL)
185+
return FAIL;
177186
}
178187
ga_append(gap, '}');
188+
d->dv_copyID = 0;
179189
}
180190
}
181191
break;
@@ -187,7 +197,9 @@ json_encode_item(garray_T *gap, typval_T *val, int copyID)
187197
break;
188198
#endif
189199
default: EMSG2(_(e_intern2), "json_encode_item()"); break;
200+
return FAIL;
190201
}
202+
return OK;
191203
}
192204

193205
/*

src/proto/json.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
/* json.c */
22
char_u *json_encode(typval_T *val);
3-
void json_encode_item(garray_T *gap, typval_T *val, int copyID);
43
void json_decode(js_read_T *reader, typval_T *res);
54
/* vim: set ft=c : */

src/testdir/test_json.vim

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ let s:varl2 = [1, 2, 3]
2727
let l2 = ['a', s:varl2, 'c']
2828
let s:varl2[1] = l2
2929
let s:varl2x = [1, ["a", [], "c"], 3]
30+
let s:jsonl3 = '[[1,2],[1,2]]'
31+
let l3 = [1, 2]
32+
let s:varl3 = [l3, l3]
3033

3134
let s:jsond1 = '{"a":1,"b":"bee","c":[1,2]}'
3235
let s:vard1 = {"a": 1, "b": "bee","c": [1,2]}
@@ -36,6 +39,9 @@ let s:vard2 = {"1": 1, "2": 2, "3": 3}
3639
let d2 = {"a": "aa", "b": s:vard2, "c": "cc"}
3740
let s:vard2["2"] = d2
3841
let s:vard2x = {"1": 1, "2": {"a": "aa", "b": {}, "c": "cc"}, "3": 3}
42+
let d3 = {"a": 1, "b": 2}
43+
let s:vard3 = {"x": d3, "y": d3}
44+
let s:jsond3 = '{"x":{"a":1,"b":2},"y":{"a":1,"b":2}}'
3945

4046
let s:jsonvals = '[true,false,,null]'
4147
let s:varvals = [v:true, v:false, v:none, v:null]
@@ -58,11 +64,16 @@ func Test_encode()
5864

5965
call assert_equal(s:jsonl1, jsonencode(s:varl1))
6066
call assert_equal(s:jsonl2, jsonencode(s:varl2))
67+
call assert_equal(s:jsonl3, jsonencode(s:varl3))
6168

6269
call assert_equal(s:jsond1, jsonencode(s:vard1))
6370
call assert_equal(s:jsond2, jsonencode(s:vard2))
71+
call assert_equal(s:jsond3, jsonencode(s:vard3))
6472

6573
call assert_equal(s:jsonvals, jsonencode(s:varvals))
74+
75+
call assert_fails('echo jsonencode(function("tr"))', 'E474:')
76+
call assert_fails('echo jsonencode([function("tr")])', 'E474:')
6677
endfunc
6778

6879
func Test_decode()
@@ -84,9 +95,11 @@ func Test_decode()
8495
call assert_equal(s:varl1, jsondecode(s:jsonl1))
8596
call assert_equal(s:varl2x, jsondecode(s:jsonl2))
8697
call assert_equal(s:varl2x, jsondecode(s:jsonl2s))
98+
call assert_equal(s:varl3, jsondecode(s:jsonl3))
8799

88100
call assert_equal(s:vard1, jsondecode(s:jsond1))
89101
call assert_equal(s:vard2x, jsondecode(s:jsond2))
102+
call assert_equal(s:vard3, jsondecode(s:jsond3))
90103

91104
call assert_equal(s:varvals, jsondecode(s:jsonvals))
92105

src/version.c

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

742742
static int included_patches[] =
743743
{ /* Add new patch number below this line */
744+
/**/
745+
1166,
744746
/**/
745747
1165,
746748
/**/

0 commit comments

Comments
 (0)