Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

json: Improve tolerance to uncovered C members during JSON encoding #53333

Conversation

lucasdietrich
Copy link
Contributor

This enhancement fixes encoding of JSON objects for which descriptors do not covers all members of the C structure represented.

Fix #50976

Signed-off-by: Lucas Dietrich [email protected]

@MaureenHelm
Copy link
Member

@mrfuchs can you please take a look?

@carlescufi carlescufi requested a review from mrfuchs March 2, 2023 16:20
@carlescufi
Copy link
Member

@mrfuchs could you please take a look? Thanks!

@MaureenHelm
Copy link
Member

@M1cha can you take a look?

Comment on lines 267 to 351
struct obj_array_array obj_array_array_ts;

ZTEST(lib_json_test, test_json_decoding_array_array)
{
int ret;
struct obj_array_array obj_array_array_ts;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change doesn't look necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, reverted that

@@ -137,6 +138,9 @@ typedef int (*json_append_bytes_t)(const char *bytes, size_t len,
__alignof__(type) == 2 ? 1 : \
__alignof__(type) == 4 ? 2 : 3)

/* Helper to get the size of a member within a struct. */
#define Z_MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how often I needed this in other zephyr projects I'd say it's finally time to add this to include/zephyr/sys/util.h with the name SIZEOF_FIELD (that's what the linux kernel calls this, just lowercase).

Comment on lines 112 to 113
size_t sub_descr_len;
uint16_t sub_descr_len;
uint16_t sub_struct_size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason for the type change and why did you choose uint16_t?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made the change to add a new field "sub_struct_size" without increasing the size of the structure
I made the hypothesis that a 16-bit unsigned integer would be sufficient to represent the values needed for these fields.
Should I use two size_t instead ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer not to touch sub_descr_len and thus keep it as size_t.

However, I'm wondering if this (unnamed) union is even the right place to add the struct size as it is primarily used to describe the descriptor (not the actual object). Couldn't we move the struct size outside of the union?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted the type for sub_descr_len to size_t.

I do agree, I moved the field sub_struct_size up and renamed it to struct_size. It just required a little more work to have all descriptors defined correctly: I needed to explicitly define the struct_size member to an arbitrary value (e.g. 0).

@carlescufi
Copy link
Member

@mrfuchs please take a look

Comment on lines 112 to 113
size_t sub_descr_len;
uint16_t sub_descr_len;
uint16_t sub_struct_size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer not to touch sub_descr_len and thus keep it as size_t.

However, I'm wondering if this (unnamed) union is even the right place to add the struct size as it is primarily used to describe the descriptor (not the actual object). Couldn't we move the struct size outside of the union?

lib/os/json.c Outdated
Comment on lines 543 to 544
} else {
field = (char *)field + elem_descr->offset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the field pointer is updated and skipped over a (unused?) field, shouldn't the last_elem variable also be updated?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this new design get_elem_size() returns the actual size of the underlying object, so last_elem correctly reflects the address of the last element.

However I'm still not convinced the way field is adjusted when parsing the nested array (when parsing an array of array).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However I'm still not convinced the way field is adjusted when parsing the nested array (when parsing an array of array).

Indeed. I hope that'll be fixed soon by #50816.

include/zephyr/sys/util.h Show resolved Hide resolved
@lucasdietrich
Copy link
Contributor Author

Did several modifications, but I still need to do additional testing.

@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@pdgendt
Copy link
Collaborator

pdgendt commented Jun 22, 2023

The align_shift member becomes obsolete if the struct size is to be used.

@pdgendt pdgendt removed the Stale label Jun 22, 2023
include/zephyr/data/json.h Show resolved Hide resolved
include/zephyr/sys/util.h Show resolved Hide resolved
tests/lib/json/src/main.c Show resolved Hide resolved
@pdgendt
Copy link
Collaborator

pdgendt commented Jun 27, 2023

@lucasdietrich care to update the PR for the latest comments, thanks

The tests in my PR #59485 succeed using this one.

@lucasdietrich
Copy link
Contributor Author

Thank you for your review, I will make the changes this evening.

@lucasdietrich lucasdietrich force-pushed the json_c_members_tolerance branch 2 times, most recently from 16b2f34 to d37204c Compare June 27, 2023 17:30
@lucasdietrich
Copy link
Contributor Author

I believe I have addressed all your remarks @mrfuchs @pdgendt.

@pdgendt
Copy link
Collaborator

pdgendt commented Jun 30, 2023

@lucasdietrich #50816 has been merged, please rebase and resolve conflicts, thanks!

@lucasdietrich
Copy link
Contributor Author

Ok, i will rebase this evening.

@lucasdietrich
Copy link
Contributor Author

Unfortunately I didn't have time to work on it yet, moreover the merge seems to be tricky.
I will need few more days.

@pdgendt
Copy link
Collaborator

pdgendt commented Jul 25, 2023

@lucasdietrich any update on this?

@lucasdietrich
Copy link
Contributor Author

After more investigation, I managed to get almost everything working except for the test "test_json_decoding_array_array", which has become a blocker for me.

I've somewhat lost track of the issue, but I can redirect my attention to it by tomorrow evening.

However, I might require some help to resolve it completely.

@lucasdietrich
Copy link
Contributor Author

lucasdietrich commented Jul 26, 2023

I managed to get almost everything working; we don't "guess" anymore the size of a structure but we compute it at build time and we use this to determine offsets.

The most tricky part was (and still is) the handling of nested arrays (array of arrays), which requires dedicated handling I'm not able to fully explain. To be honest I tried to have the unit tests working rather than designing an accurate solution for nested arrays. This is where I would greatly benefit from external insight. Consequently this has left the following key issue unresolved :

Yet, the member of the structure describing the nested array should remain at the start of the structure. Using the "test_json_encoding_array_array" test as example: I'm not yet able to calculate the correct offset of "objects" within the "struct array". Consequently the test fails (crashes) if we uncomment the line. Actually I don't fully understand when the adjustment should be made.

To conclude, I've successfully tested these commits with a personnal project.

@lucasdietrich lucasdietrich force-pushed the json_c_members_tolerance branch 2 times, most recently from cf38367 to 5b088a1 Compare July 26, 2023 17:40
@lucasdietrich
Copy link
Contributor Author

I've just rebased and noticed that the new tests introduced in #60046 are failing with the current changes(2 dim array encoding). I'll need more time to address this issue.

This macro is used to get the size of a specific field in a structure type.
It will return the size of the field in bytes.

Signed-off-by: Lucas Dietrich <[email protected]>
Enable the computation of a struct member's size during compile-time to
enhance accuracy, removing the need for speculative size determinations
during runtime.

Signed-off-by: Lucas Dietrich <[email protected]>
Add special handling for nested arrays

This enhancement fix encoding of JSON objects for which descriptors do
not covers all members of the C structure represented.

Fixes zephyrproject-rtos#50976

Signed-off-by: Lucas Dietrich <[email protected]>
This commit updates various structs in the JSON test suite to include
unused members. These additions aim to test the improved tolerance of
JSON encoding for C struct members that may not be fully described by
JSON descriptors.

As a consequence of the addition of unused fields,
prefer designated initializers instead of postionnal ones.

Add a note about a test which constantly fails with a unused field.

Signed-off-by: Lucas Dietrich <[email protected]>
@github-actions
Copy link

This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time.

@github-actions github-actions bot added the Stale label Sep 25, 2023
@github-actions github-actions bot closed this Oct 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Base OS Base OS Library (lib/os) area: JSON Stale
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JSON array encoding fails on array of objects
8 participants