From 4a35a75b64bfc1cf47dec2d4627eb502da23fe63 Mon Sep 17 00:00:00 2001 From: Seven Du Date: Thu, 10 Dec 2020 03:10:41 +0800 Subject: [PATCH] json: fix raw json string decoding crash when expected key is missing (#7206) --- vlib/builtin/string.v | 16 ++++++++++++++++ vlib/json/json_test.v | 41 +++++++++++++++++++++++++++++++++++++++++ vlib/v/gen/json.v | 4 ++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 7d221e3035..eb95f38f0d 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -111,6 +111,22 @@ pub fn tos3(s charptr) string { } } +// Same as `tos2`, but returns empty string on nil ptr +pub fn tos4(s byteptr) string { + if s == 0 { + return "" + } + return tos2(s) +} + +// Same as `tos4`, but for char*, to avoid warnings +pub fn tos5(s charptr) string { + if s == 0 { + return "" + } + return tos3(s) +} + [deprecated] pub fn tos_lit(s charptr) string { eprintln('warning: `tos_lit` has been deprecated, use `_SLIT` instead') diff --git a/vlib/json/json_test.v b/vlib/json/json_test.v index 221c425608..cc042e6ebe 100644 --- a/vlib/json/json_test.v +++ b/vlib/json/json_test.v @@ -111,6 +111,15 @@ fn test_raw_json_field() { assert color.space == 'YCbCr' } +fn test_bad_raw_json_field() { + color := json.decode(Color, '{"space": "YCbCr"}') or { + println('text') + return + } + assert color.point == '' + assert color.space == 'YCbCr' +} + struct City { name string } @@ -310,3 +319,35 @@ fn test_encode_alias_struct() { out := json.encode(msg) assert out == expected } + +struct List { + id int + items []string +} + +fn test_list() { + list := json.decode(List, '{"id": 1, "items": ["1", "2"]}') or { + println('error') + return + } + assert list.id == 1 + assert list.items == ["1", "2"] +} + +fn test_list_no_id() { + list := json.decode(List, '{"items": ["1", "2"]}') or { + println('error') + return + } + assert list.id == 0 + assert list.items == ["1", "2"] +} + +fn test_list_no_items() { + list := json.decode(List, '{"id": 1}') or { + println('error') + return + } + assert list.id == 1 + assert list.items == [] +} diff --git a/vlib/v/gen/json.v b/vlib/v/gen/json.v index 88fc0ba4b3..7ed319fe6d 100644 --- a/vlib/v/gen/json.v +++ b/vlib/v/gen/json.v @@ -127,7 +127,7 @@ fn (mut g Gen) gen_struct_enc_dec(type_info table.TypeInfo, styp string, mut enc field_type := g.typ(field.typ) field_sym := g.table.get_type_symbol(field.typ) if field.attrs.contains('raw') { - dec.writeln('\tres.${c_name(field.name)} = tos2(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));') + dec.writeln('\tres.${c_name(field.name)} = tos4(cJSON_PrintUnformatted(' + 'js_get(root, "$name")));') } else { // Now generate decoders for all field types in this struct // need to do it here so that these functions are generated first @@ -211,7 +211,7 @@ fn (mut g Gen) decode_array(value_type table.Type) string { ' } return ' - if(!cJSON_IsArray(root)) { + if(root && !cJSON_IsArray(root)) { Option err = v_error( string_add(_SLIT("Json element is not an array: "), tos2(cJSON_PrintUnformatted(root))) ); return *(Option_array_$styp *)&err; }