From de6b69c67618e2b56b33579178a4a5194de4c551 Mon Sep 17 00:00:00 2001 From: Lucas Dietrich Date: Mon, 3 Apr 2023 23:17:37 +0200 Subject: [PATCH] json: Improve tolerance to uncovered C members during JSON encoding This enhancement fix encoding of JSON objects for which descriptors do not covers all members of the C structure represented. Introduce SIZEOF_FIELD helper macro Fixes #50976 Signed-off-by: Lucas Dietrich --- include/zephyr/data/json.h | 14 ++++++++++---- include/zephyr/sys/util.h | 20 ++++++++++++++++++++ lib/os/json.c | 13 +++---------- tests/lib/json/src/main.c | 9 +++++++++ 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/include/zephyr/data/json.h b/include/zephyr/data/json.h index 65c9096cb020ddd..818b07d8caac7f5 100644 --- a/include/zephyr/data/json.h +++ b/include/zephyr/data/json.h @@ -109,7 +109,8 @@ struct json_obj_descr { union { struct { const struct json_obj_descr *sub_descr; - size_t sub_descr_len; + uint16_t sub_descr_len; + uint16_t sub_struct_size; } object; struct { const struct json_obj_descr *element_descr; @@ -201,6 +202,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .object = { \ .sub_descr = sub_descr_, \ .sub_descr_len = ARRAY_SIZE(sub_descr_), \ + .sub_struct_size = sizeof(struct_), \ }, \ }, \ } @@ -245,11 +247,12 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, * @param elem_descr_ Element descriptor, pointer to a descriptor array * @param elem_descr_len_ Number of elements in elem_descr_ */ -#define Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_) \ +#define Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_, struct_size_) \ { \ .object = { \ .sub_descr = elem_descr_, \ .sub_descr_len = elem_descr_len_, \ + .sub_struct_size = struct_size_, \ }, \ } @@ -338,7 +341,8 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .array = { \ .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ JSON_TOK_OBJECT_START, \ - Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ + Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_, \ + SIZEOF_FIELD(struct_, field_name_[0]))), \ .n_elements = (max_len_), \ }, \ }, \ @@ -456,6 +460,7 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .object = { \ .sub_descr = sub_descr_, \ .sub_descr_len = ARRAY_SIZE(sub_descr_), \ + .sub_struct_size = sizeof(struct_), \ }, \ }, \ } @@ -548,7 +553,8 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len, .array = { \ .element_descr = Z_JSON_ELEMENT_DESCR(struct_, len_field_, \ JSON_TOK_OBJECT_START, \ - Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_)), \ + Z_JSON_DESCR_OBJ(elem_descr_, elem_descr_len_, \ + SIZEOF_FIELD(struct_, field_name_[0])), \ .n_elements = (max_len_), \ }, \ }, \ diff --git a/include/zephyr/sys/util.h b/include/zephyr/sys/util.h index fdc4532cf8ceaed..22d09b32b2562b5 100644 --- a/include/zephyr/sys/util.h +++ b/include/zephyr/sys/util.h @@ -210,6 +210,26 @@ extern "C" { #define CONTAINER_OF(ptr, type, field) \ ((type *)(((char *)(ptr)) - offsetof(type, field))) +/** + * @brief Get the size of a field in a structure type + * + * Example: + * + * struct foo { + * int bar; + * char baz; + * }; + * + * size_t size_of_baz = SIZEOF_FIELD(struct foo, baz); + * + * Above, @p size_of_baz is equal to sizeof(char). + * + * @param type the type of the structure containing the field + * @param member the name of the field in the structure + * @return the size of the field in bytes + */ +#define SIZEOF_FIELD(type, member) sizeof(((type *)0)->member) + /** * @brief Value of @p x rounded up to the next multiple of @p align, * which must be a power of 2. diff --git a/lib/os/json.c b/lib/os/json.c index 3e9ffbee61581ab..3a5c6c3e313a19b 100644 --- a/lib/os/json.c +++ b/lib/os/json.c @@ -522,16 +522,7 @@ static ptrdiff_t get_elem_size(const struct json_obj_descr *descr) case JSON_TOK_ARRAY_START: return descr->array.n_elements * get_elem_size(descr->array.element_descr); case JSON_TOK_OBJECT_START: { - ptrdiff_t total = 0; - size_t i; - - for (i = 0; i < descr->object.sub_descr_len; i++) { - ptrdiff_t s = get_elem_size(&descr->object.sub_descr[i]); - - total += ROUND_UP(s, 1 << descr->align_shift); - } - - return total; + return descr->object.sub_struct_size; } default: return -EINVAL; @@ -549,6 +540,8 @@ static int arr_parse(struct json_obj *obj, if (val) { elements = (size_t *)((char *)val + elem_descr->offset); + } else { + field = (char *)field + elem_descr->offset; } __ASSERT_NO_MSG(elem_size > 0); diff --git a/tests/lib/json/src/main.c b/tests/lib/json/src/main.c index 0171c85bbb6c98b..b2dbbeede3b5aa5 100644 --- a/tests/lib/json/src/main.c +++ b/tests/lib/json/src/main.c @@ -11,6 +11,7 @@ struct test_nested { int nested_int; + uint32_t _unused_member; bool nested_bool; const char *nested_string; }; @@ -19,6 +20,7 @@ struct test_struct { const char *some_string; int some_int; bool some_bool; + uint32_t _unused_member; struct test_nested some_nested_struct; int some_array[16]; size_t some_array_len; @@ -30,17 +32,20 @@ struct test_struct { }; struct elt { + uint32_t _unused_member; const char *name; int height; }; struct obj_array { struct elt elements[10]; + uint32_t _unused_member; size_t num_elements; }; struct test_int_limits { int int_max; + uint32_t _unused_member; int int_cero; int int_min; }; @@ -88,11 +93,15 @@ static const struct json_obj_descr obj_limits_descr[] = { }; struct array { + uint32_t _unused_member1; + uint32_t _unused_member2; struct elt objects; }; struct obj_array_array { + uint32_t _unused_member1; struct array objects_array[4]; + uint32_t _unused_member2; size_t objects_array_len; };