From e057b38e7037808b3593fb1035794595b4e4a45e Mon Sep 17 00:00:00 2001 From: Emanuel Date: Wed, 6 Dec 2023 16:56:04 +0100 Subject: fix(json): allow objects with empty keys #25564 Problem: Empty string is a valid JSON key, but json_decode() treats an object with empty key as ":help msgpack-special-dict". #20757 :echo json_decode('{"": "1"}') {'_TYPE': [], '_VAL': [['', '1']]} Note: vim returns `{'': '1'}`. Solution: Allow empty string as an object key. Note that we still (currently) disallow empty keys in object_to_vim() (since 7c01d5ff9286d262097484c680e3a4eab49e2911): https://github.com/neovim/neovim/blob/f64e4b43e1191ff30d902730f752875aa55682ce/src/nvim/api/private/converter.c#L333-L334 Fix #20757 Co-authored-by: Justin M. Keyes --- src/nvim/eval.lua | 4 +--- src/nvim/eval/decode.c | 14 ++------------ 2 files changed, 3 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 59423808be..51cf7bb0ea 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -5735,8 +5735,7 @@ M.funcs = { Vim value. In the following cases it will output |msgpack-special-dict|: 1. Dictionary contains duplicate key. - 2. Dictionary contains empty key. - 3. String contains NUL byte. Two special dictionaries: for + 2. String contains NUL byte. Two special dictionaries: for dictionary and for string will be emitted in case string with NUL byte was a dictionary key. @@ -7155,7 +7154,6 @@ M.funcs = { are binary strings). 2. String with NUL byte inside. 3. Duplicate key. - 4. Empty key. ext |List| with two values: first is a signed integer representing extension type. Second is |readfile()|-style list of strings. diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c index a6407693d7..64b65b42a5 100644 --- a/src/nvim/eval/decode.c +++ b/src/nvim/eval/decode.c @@ -141,9 +141,7 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack ValuesStackItem key = kv_pop(*stack); if (last_container.special_val == NULL) { // These cases should have already been handled. - assert(!(key.is_special_string - || key.val.vval.v_string == NULL - || *key.val.vval.v_string == NUL)); + assert(!(key.is_special_string || key.val.vval.v_string == NULL)); dictitem_T *const obj_di = tv_dict_item_alloc(key.val.vval.v_string); tv_clear(&key.val); if (tv_dict_add(last_container.container.vval.v_dict, obj_di) @@ -170,11 +168,10 @@ static inline int json_decoder_pop(ValuesStackItem obj, ValuesStack *const stack tv_clear(&obj.val); return FAIL; } - // Handle empty key and key represented as special dictionary + // Handle special dictionaries if (last_container.special_val == NULL && (obj.is_special_string || obj.val.vval.v_string == NULL - || *obj.val.vval.v_string == NUL || tv_dict_find(last_container.container.vval.v_dict, obj.val.vval.v_string, -1))) { tv_clear(&obj.val); @@ -404,13 +401,6 @@ static inline int parse_json_string(const char *const buf, const size_t buf_len, semsg(_("E474: Expected string end: %.*s"), (int)buf_len, buf); goto parse_json_string_fail; } - if (len == 0) { - POP(((typval_T) { - .v_type = VAR_STRING, - .vval = { .v_string = NULL }, - }), false); - goto parse_json_string_ret; - } char *str = xmalloc(len + 1); int fst_in_pair = 0; char *str_end = str; -- cgit