From b57e1a1f7feb6c1cbb18c893c42ad3140028e137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98yvind=20R=C3=B8nningstad?= Date: Thu, 18 Apr 2024 13:04:43 +0000 Subject: [PATCH] zcbor_decode: Redesign the fragment decoding API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Place fragments in the state struct so the user doesn't need to keep track of them. Signed-off-by: Øyvind Rønningstad --- README.md | 1 + include/zcbor_common.h | 39 ++++- include/zcbor_decode.h | 64 ++++---- src/zcbor_common.c | 112 ++++++++++++-- src/zcbor_decode.c | 171 ++++++++++++--------- src/zcbor_print.c | 3 + tests/fuzz/main_entry.c | 2 +- tests/unit/test1_unit_tests/CMakeLists.txt | 1 + tests/unit/test1_unit_tests/src/main.c | 72 ++++----- 9 files changed, 296 insertions(+), 169 deletions(-) diff --git a/README.md b/README.md index 79ae6130..212c2d19 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ Name | Description `ZCBOR_STOP_ON_ERROR` | Enable the `stop_on_error` functionality. This makes all functions abort their execution if called when an error has already happened. `ZCBOR_BIG_ENDIAN` | All decoded values are returned as big-endian. The default is little-endian. `ZCBOR_MAP_SMART_SEARCH` | Applies to decoding of unordered maps. When enabled, a flag is kept for each element in an array, ensuring it is not processed twice. If disabled, a count is kept for map as a whole. Enabling increases code size and memory usage, and requires the state variable to possess the memory necessary for the flags. +`ZCBOR_FRAGMENTS` | Enable functions for decoding and encoding byte and text strings in fragments. Python script and module diff --git a/include/zcbor_common.h b/include/zcbor_common.h index ccdcb97f..531c205a 100644 --- a/include/zcbor_common.h +++ b/include/zcbor_common.h @@ -107,6 +107,18 @@ union { bool payload_moved; /**< Is set to true while the state is stored as a backup if @ref zcbor_update_state is called, since that function updates the payload_end of all backed-up states. */ + bool inside_cbor_bstr; /**< True if we are currently inside a CBOR-encoded bstr, + i.e. that as been started with zcbor_bstr_start_*(), or + `zcbor_cbor_bstr_fragments_start_*()`. */ +#ifdef ZCBOR_FRAGMENTS + bool inside_frag_str; /**< True if we are currently inside a fragmented (non-CBOR-encoded) + string. This is mutually exclusive with `inside_cbor_bstr`, + i.e. not set when using `zcbor_cbor_bstr_fragments_start_*()` */ + ptrdiff_t frag_offset; /**< The offset in the current string at which this payload section starts. */ + size_t str_total_len; /**< The total length of the string this fragment is a part of. */ + ptrdiff_t frag_offset_cbor; /**< The offset in the current string at which this payload section starts. */ + size_t str_total_len_cbor; /**< The total length of the string this fragment is a part of. */ +#endif /* This is the "decode state", the part of zcbor_state_t that is only used by zcbor_decode.c. */ struct { @@ -152,6 +164,7 @@ struct zcbor_state_constant { #ifdef ZCBOR_MAP_SMART_SEARCH uint8_t *map_search_elem_state_end; /**< The end of the @ref map_search_elem_state buffer. */ #endif + const uint8_t *curr_payload_section; /**< The currently encoded/decoded fragment. */ }; #ifdef ZCBOR_CANONICAL @@ -283,6 +296,9 @@ do { \ #define ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE 20 #define ZCBOR_ERR_INVALID_VALUE_ENCODING 21 ///! When ZCBOR_CANONICAL is defined, and the incoming data is not encoded with minimal length, or uses indefinite length array. #define ZCBOR_ERR_CONSTANT_STATE_MISSING 22 +#define ZCBOR_ERR_INNER_STRING_TOO_LARGE 23 +#define ZCBOR_ERR_NOT_IN_FRAGMENT 24 +#define ZCBOR_ERR_INSIDE_STRING 25 #define ZCBOR_ERR_UNKNOWN 31 /** The largest possible elem_count. */ @@ -390,17 +406,23 @@ static inline void zcbor_error(zcbor_state_t *state, int err) } } -/** Whether the current payload is exhausted. */ +/** Whether the current payload (section) is exhausted. */ static inline bool zcbor_payload_at_end(const zcbor_state_t *state) { return (state->payload == state->payload_end); } -/** Update the current payload pointer (and payload_end). +/** Introduce a new payload section. * + * Updates the current payload pointer (and payload_end and frag_offset(_cbor)). * For use when the payload is divided into multiple chunks. * - * This function also updates all backups to the new payload_end. + * This function also updates all backups to the new payload_end, + * and also updates the frag_offset/frag_offset_cbor of all backups. + * + * Note that if this is called before the current payload is exhausted, the + * remaining payload will be abandoned. + * * This sets a flag so that @ref zcbor_process_backup fails if a backup is * processed with the flag @ref ZCBOR_FLAG_RESTORE, but without the flag * @ref ZCBOR_FLAG_KEEP_PAYLOAD since this would cause an invalid state. @@ -413,6 +435,17 @@ static inline bool zcbor_payload_at_end(const zcbor_state_t *state) void zcbor_update_state(zcbor_state_t *state, const uint8_t *payload, size_t payload_len); +/** Get the the offset into the current string at which the current payload + * pointer (state->payload) belongs. */ +size_t zcbor_current_string_offset(zcbor_state_t *state); + +/** Get the remaining number of bytes in the current string, calculated from + * the current payload pointer (state->payload). */ +size_t zcbor_current_string_remainder(zcbor_state_t *state); + +/** Can be used on any fragment to tell if it is the final fragment of its string. */ +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); + /** Check that the provided fragments are complete and in the right order. * * If the total length is not known, the total_len can have the value diff --git a/include/zcbor_decode.h b/include/zcbor_decode.h index 90319d21..a9c9bcc1 100644 --- a/include/zcbor_decode.h +++ b/include/zcbor_decode.h @@ -371,7 +371,9 @@ bool zcbor_tstr_expect_term(zcbor_state_t *state, char const *str, size_t maxlen /** Decode and consume a bstr header. * * The rest of the string can be decoded as CBOR. - * A state backup is created to keep track of the element count. + * A state backup is created to keep track of the element count and original payload_end. + * payload_end is set to the end of the string, so when the payload is exhausted, + * the string is considered fully decoded. * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. * * @param[inout] state The current state of the decoding. @@ -393,49 +395,45 @@ bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result); bool zcbor_bstr_end_decode(zcbor_state_t *state); -/** Supplementary string (bstr/tstr) decoding functions for fragmented payloads: */ +#ifdef ZCBOR_FRAGMENTS -/** Start decoding a bstr/tstr, even if the payload contains only part of it. - * - * This must be followed by a call to @ref zcbor_update_state, which can be - * followed by a call to @ref zcbor_next_fragment. Do not call this function - * again on subsequent fragments of the same string. +/** Start decoding a fragmented string. I.e. a string spread over non-consecutive payload sections. * - * This consumes the remaining payload as long as it belongs to the string. + * After calling this, you can retrieve a fragment with @ref zcbor_str_fragment_decode, + * then update the payload with @ref zcbor_update_state. + * Repeat until the string is fully decoded, then call @ref zcbor_bstr_fragments_end_decode. */ -bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); -bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result); +bool zcbor_bstr_fragments_start_decode(zcbor_state_t *state); +bool zcbor_tstr_fragments_start_decode(zcbor_state_t *state); -/** Extract the next fragment of a string. +/** Start decoding a fragmented CBOR-encoded bytestring. * - * Use this function to extract all but the first fragment. - */ -void zcbor_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); - -/** Decode and consume a bstr header, assuming the payload does not contain the whole bstr. + * I.e. a string spread over non-consecutive payload sections. * - * The rest of the string can be decoded as CBOR. - * A state backup is created to keep track of the element count. - * Call @ref zcbor_update_state followed by @ref zcbor_bstr_next_fragment when - * the current payload has been exhausted. - * Call @ref zcbor_bstr_end_decode when done decoding the contents of the bstr. + * This is an alternative to zcbor_*str_fragments_start_decode() to be used if the payload + * contains CBOR data that will be decoded directly with other zcbor_*() functions. + * + * A state backup is created to keep track of the element count and original payload_end. + * After calling this, you can decode elements using other zcbor functions, + * then update the payload with @ref zcbor_update_state. + * Do not use @ref zcbor_str_fragment_decode with this function. + * Repeat until the string is fully decoded, then call @ref zcbor_bstr_fragments_end_decode. + * When the current payload section contains the end of the string, + * payload_end is set to the end of the string, so there is no risk of decoding past the end. */ -bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *result); +bool zcbor_cbor_bstr_fragments_start_decode(zcbor_state_t *state); -/** Start decoding the next fragment of a string. +/** Retrieve a string fragment. * - * Use this function to extract all but the first fragment of a CBOR-encoded - * bstr. + * Consume bytes from the payload until either the end of the payload or the end of the string. + * Do not use this function with @ref zcbor_cbor_bstr_fragments_start_decode. */ -void zcbor_bstr_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result); +bool zcbor_str_fragment_decode(zcbor_state_t *state, struct zcbor_string_fragment *fragment); + +/** Finish decoding a fragmented string. */ +bool zcbor_str_fragments_end_decode(zcbor_state_t *state); -/** Can be used on any fragment to tell if it is the final fragment of the string. */ -bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment); +#endif /* ZCBOR_FRAGMENTS */ #ifdef __cplusplus } diff --git a/src/zcbor_common.c b/src/zcbor_common.c index 5bf959e6..e515245d 100644 --- a/src/zcbor_common.c +++ b/src/zcbor_common.c @@ -34,8 +34,7 @@ bool zcbor_new_backup(zcbor_state_t *state, size_t new_elem_count) * backup would be unused. */ size_t i = (state->constant_state->current_backup) - 1; - memcpy(&state->constant_state->backup_list[i], state, - sizeof(zcbor_state_t)); + state->constant_state->backup_list[i] = *state; state->elem_count = new_elem_count; @@ -69,8 +68,7 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, ZCBOR_ERR(ZCBOR_ERR_PAYLOAD_OUTDATED); } } - memcpy(state, &state->constant_state->backup_list[i], - sizeof(zcbor_state_t)); + *state = state->constant_state->backup_list[i]; } if (flags & ZCBOR_FLAG_CONSUME) { @@ -92,17 +90,11 @@ bool zcbor_process_backup(zcbor_state_t *state, uint32_t flags, state->decode_state = local_copy.decode_state; } - return true; -} + if (state->inside_cbor_bstr) { -static void update_backups(zcbor_state_t *state, uint8_t const *new_payload_end) -{ - if (state->constant_state) { - for (unsigned int i = 0; i < state->constant_state->current_backup; i++) { - state->constant_state->backup_list[i].payload_end = new_payload_end; - state->constant_state->backup_list[i].payload_moved = true; - } } + + return true; } @@ -123,6 +115,7 @@ bool zcbor_union_elem_code(zcbor_state_t *state) return true; } + bool zcbor_union_end_code(zcbor_state_t *state) { if (!zcbor_process_backup(state, ZCBOR_FLAG_CONSUME, state->elem_count)) { @@ -131,6 +124,7 @@ bool zcbor_union_end_code(zcbor_state_t *state) return true; } + void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, const uint8_t *payload, size_t payload_len, size_t elem_count, uint8_t *flags, size_t flags_bytes) @@ -147,6 +141,14 @@ void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, state_array[0].decode_state.map_elems_processed = 0; (void)flags; (void)flags_bytes; +#endif + state_array[0].inside_cbor_bstr = false; +#ifdef ZCBOR_FRAGMENTS + state_array[0].inside_frag_str = false; + state_array[0].frag_offset = 0; + state_array[0].str_total_len = payload_len; + state_array[0].frag_offset_cbor = 0; + state_array[0].str_total_len_cbor = payload_len; #endif state_array[0].constant_state = NULL; @@ -167,19 +169,95 @@ void zcbor_new_state(zcbor_state_t *state_array, size_t n_states, state_array[0].constant_state->manually_process_elem = ZCBOR_MANUALLY_PROCESS_ELEM_DEFAULT; #ifdef ZCBOR_MAP_SMART_SEARCH state_array[0].constant_state->map_search_elem_state_end = flags + flags_bytes; +#endif +#ifdef ZCBOR_FRAGMENTS + state_array[0].constant_state->curr_payload_section = payload; #endif if (n_states > 2) { state_array[0].constant_state->backup_list = &state_array[1]; } } -void zcbor_update_state(zcbor_state_t *state, - const uint8_t *payload, size_t payload_len) + +static void update_state(zcbor_state_t *state, const uint8_t *payload, size_t payload_len) { + const uint8_t *old_payload = state->payload; + state->payload = payload; - state->payload_end = payload + payload_len; + (void)old_payload; +#ifdef ZCBOR_FRAGMENTS + ptrdiff_t prev_len = old_payload - state->constant_state->curr_payload_section; + + state->frag_offset += prev_len; + state->frag_offset_cbor += prev_len; + if (state->inside_cbor_bstr) { + state->payload_end = payload + MIN(payload_len, + (size_t)((ptrdiff_t)state->str_total_len_cbor - state->frag_offset_cbor)); + } else +#endif + { + state->payload_end = payload + payload_len; + } +} + + +static void update_backups(zcbor_state_t *state, const uint8_t *old_payload, size_t new_payload_len) +{ + for (unsigned int i = 0; i < state->constant_state->current_backup; i++) { + state->constant_state->backup_list[i].payload = old_payload; + update_state(&state->constant_state->backup_list[i], state->payload, new_payload_len); + state->constant_state->backup_list[i].payload_moved = true; + } +} - update_backups(state, state->payload_end); + +void zcbor_update_state(zcbor_state_t *state, const uint8_t *payload, size_t payload_len) +{ + const uint8_t *old_payload = state->payload; + update_state(state, payload, payload_len); + update_backups(state, old_payload, payload_len); + state->constant_state->curr_payload_section = payload; +} + + +#ifdef ZCBOR_FRAGMENTS +size_t zcbor_current_string_offset(zcbor_state_t *state) +{ + ptrdiff_t res; + + if (state->inside_frag_str) { + zcbor_assert((state->payload >= state->constant_state->curr_payload_section) + && (state->payload < (state->constant_state->curr_payload_section + state->str_total_len)), + "Payload not within fragment\n"); + res = ((state->payload - state->constant_state->curr_payload_section) + + state->frag_offset); + } else { + zcbor_assert((state->payload >= state->constant_state->curr_payload_section) + && (state->payload < (state->constant_state->curr_payload_section + state->str_total_len_cbor)), + "Payload not within fragment\n"); + res = ((state->payload - state->constant_state->curr_payload_section) + + state->frag_offset_cbor); + } + zcbor_assert(res >= 0, "Negative offset\n"); + return (size_t)res; +} + + +size_t zcbor_current_string_remainder(zcbor_state_t *state) +{ + size_t curr_offset = zcbor_current_string_offset(state); + if (state->inside_frag_str) { + return state->str_total_len - curr_offset; + } else { + return state->str_total_len_cbor - curr_offset; + } +} +#endif + + +bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment) +{ + return (fragment->total_len == (fragment->offset + fragment->fragment.len)); } diff --git a/src/zcbor_decode.c b/src/zcbor_decode.c index f287f2d5..bd0e4b2a 100644 --- a/src/zcbor_decode.c +++ b/src/zcbor_decode.c @@ -36,6 +36,9 @@ static bool initial_checks(zcbor_state_t *state) { ZCBOR_CHECK_ERROR(); ZCBOR_CHECK_PAYLOAD(); +#ifdef ZCBOR_FRAGMENTS + ZCBOR_ERR_IF(state->inside_frag_str, ZCBOR_ERR_INSIDE_STRING); +#endif return true; } @@ -68,6 +71,23 @@ do {\ } \ } while(0) + +#ifdef ZCBOR_FRAGMENTS +static bool initial_check_inside_frag_str(zcbor_state_t *state) +{ + ZCBOR_CHECK_ERROR(); + ZCBOR_CHECK_PAYLOAD(); + return true; +} + +#define INITIAL_CHECKS_INSIDE_FRAG_STR() \ +do {\ + if (!initial_check_inside_frag_str(state)) { \ + ZCBOR_FAIL(); \ + } \ +} while(0) +#endif + static void err_restore(zcbor_state_t *state, int err) { state->payload = state->payload_bak; @@ -486,6 +506,8 @@ bool zcbor_bstr_start_decode(zcbor_state_t *state, struct zcbor_string *result) } state->payload_end = result->value + result->len; + state->inside_cbor_bstr = true; + return true; } @@ -504,102 +526,123 @@ bool zcbor_bstr_end_decode(zcbor_state_t *state) } -static void partition_fragment(const zcbor_state_t *state, - struct zcbor_string_fragment *result) -{ - result->fragment.len = MIN(result->fragment.len, - (size_t)state->payload_end - (size_t)state->payload); -} - +#ifdef ZCBOR_FRAGMENTS -static bool start_decode_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *result, - zcbor_major_type_t exp_major_type) +static bool start_decode_fragments(zcbor_state_t *state, + zcbor_major_type_t exp_major_type, bool cbor_bstr) { - PRINT_FUNC(); - if(!str_start_decode(state, &result->fragment, exp_major_type)) { + struct zcbor_string string_hdr; + + if(!str_start_decode(state, &string_hdr, exp_major_type)) { ZCBOR_FAIL(); } - result->offset = 0; - result->total_len = result->fragment.len; - partition_fragment(state, result); - state->payload_end = state->payload + result->fragment.len; + if (state->inside_cbor_bstr) { + if (zcbor_current_string_remainder(state) < string_hdr.len) { + ERR_RESTORE(ZCBOR_ERR_INNER_STRING_TOO_LARGE); + } + } + + ptrdiff_t new_offset = state->constant_state->curr_payload_section - state->payload; + + if (cbor_bstr) { + if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) { + FAIL_RESTORE(); + } + state->frag_offset_cbor = new_offset; + state->str_total_len_cbor = string_hdr.len; + state->inside_cbor_bstr = true; + } else { + state->frag_offset = new_offset; + state->str_total_len = string_hdr.len; + state->inside_frag_str = true; + } return true; } -bool zcbor_bstr_start_decode_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *result) + +bool zcbor_bstr_fragments_start_decode(zcbor_state_t *state) { PRINT_FUNC(); - if (!start_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR)) { - ZCBOR_FAIL(); - } - if (!zcbor_new_backup(state, ZCBOR_MAX_ELEM_COUNT)) { - FAIL_RESTORE(); - } - return true; + return start_decode_fragments(state, ZCBOR_MAJOR_TYPE_BSTR, false); } -void zcbor_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result) +bool zcbor_tstr_fragments_start_decode(zcbor_state_t *state) { - memcpy(result, prev_fragment, sizeof(*result)); - result->fragment.value = state->payload_mut; - result->offset += prev_fragment->fragment.len; - result->fragment.len = result->total_len - result->offset; + PRINT_FUNC(); + return start_decode_fragments(state, ZCBOR_MAJOR_TYPE_TSTR, false); +} - partition_fragment(state, result); - zcbor_log("New fragment length %zu\r\n", result->fragment.len); - state->payload += result->fragment.len; +bool zcbor_cbor_bstr_fragments_start_decode(zcbor_state_t *state) +{ + PRINT_FUNC(); + return start_decode_fragments(state, ZCBOR_MAJOR_TYPE_BSTR, true); } -void zcbor_bstr_next_fragment(zcbor_state_t *state, - struct zcbor_string_fragment *prev_fragment, - struct zcbor_string_fragment *result) +bool zcbor_str_fragment_decode(zcbor_state_t *state, struct zcbor_string_fragment *fragment) { - memcpy(result, prev_fragment, sizeof(*result)); - result->fragment.value = state->payload_mut; - result->offset += prev_fragment->fragment.len; - result->fragment.len = result->total_len - result->offset; + PRINT_FUNC(); + INITIAL_CHECKS_INSIDE_FRAG_STR(); - partition_fragment(state, result); - zcbor_log("fragment length %zu\r\n", result->fragment.len); - state->payload_end = state->payload + result->fragment.len; -} + ZCBOR_ERR_IF(!state->inside_frag_str && !state->inside_cbor_bstr, ZCBOR_ERR_NOT_IN_FRAGMENT); + // ZCBOR_ERR_IF(!state->inside_frag_str, ZCBOR_ERR_NOT_IN_FRAGMENT); + size_t len; -bool zcbor_is_last_fragment(const struct zcbor_string_fragment *fragment) -{ - return (fragment->total_len == (fragment->offset + fragment->fragment.len)); + if (state->inside_frag_str) { + len = MIN((size_t)state->payload_end - (size_t)state->payload, + zcbor_current_string_remainder(state)); + state->payload += len; + fragment->total_len = state->str_total_len; + } else { + len = MIN((size_t)state->payload - (size_t)state->constant_state->curr_payload_section, + zcbor_current_string_offset(state)); + fragment->total_len = state->str_total_len_cbor; + } + + fragment->fragment.value = state->payload - len; + fragment->fragment.len = len; + + fragment->offset = zcbor_current_string_offset(state) - len; + + return true; } -static bool str_decode(zcbor_state_t *state, struct zcbor_string *result, - zcbor_major_type_t exp_major_type) +bool zcbor_str_fragments_end_decode(zcbor_state_t *state) { - if (!str_start_decode_with_overflow_check(state, result, exp_major_type)) { - ZCBOR_FAIL(); + PRINT_FUNC(); + + ZCBOR_ERR_IF(!state->inside_frag_str && !state->inside_cbor_bstr, ZCBOR_ERR_NOT_IN_FRAGMENT); + ZCBOR_ERR_IF(zcbor_current_string_remainder(state) != 0, ZCBOR_ERR_NOT_AT_END); + + if (state->inside_frag_str) { + state->inside_frag_str = false; + } else { + if (!zcbor_bstr_end_decode(state)) { + ZCBOR_FAIL(); + } + state->inside_cbor_bstr = false; } - state->payload += result->len; return true; } +#endif /* ZCBOR_FRAGMENTS */ + -static bool str_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result, +static bool str_decode(zcbor_state_t *state, struct zcbor_string *result, zcbor_major_type_t exp_major_type) { - if (!start_decode_fragment(state, result, exp_major_type)) { + if (!str_start_decode_with_overflow_check(state, result, exp_major_type)) { ZCBOR_FAIL(); } - (state->payload) += result->fragment.len; + state->payload += result->len; return true; } @@ -626,13 +669,6 @@ bool zcbor_bstr_decode(zcbor_state_t *state, struct zcbor_string *result) } -bool zcbor_bstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) -{ - PRINT_FUNC(); - return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_BSTR); -} - - bool zcbor_bstr_expect(zcbor_state_t *state, struct zcbor_string *expected) { PRINT_FUNC(); @@ -647,13 +683,6 @@ bool zcbor_tstr_decode(zcbor_state_t *state, struct zcbor_string *result) } -bool zcbor_tstr_decode_fragment(zcbor_state_t *state, struct zcbor_string_fragment *result) -{ - PRINT_FUNC(); - return str_decode_fragment(state, result, ZCBOR_MAJOR_TYPE_TSTR); -} - - bool zcbor_tstr_expect(zcbor_state_t *state, struct zcbor_string *expected) { PRINT_FUNC(); diff --git a/src/zcbor_print.c b/src/zcbor_print.c index d62f2780..dfd78ad9 100644 --- a/src/zcbor_print.c +++ b/src/zcbor_print.c @@ -93,6 +93,9 @@ const char *zcbor_error_str(int error) ZCBOR_ERR_CASE(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE) ZCBOR_ERR_CASE(ZCBOR_ERR_INVALID_VALUE_ENCODING) ZCBOR_ERR_CASE(ZCBOR_ERR_CONSTANT_STATE_MISSING) + ZCBOR_ERR_CASE(ZCBOR_ERR_INNER_STRING_TOO_LARGE) + ZCBOR_ERR_CASE(ZCBOR_ERR_NOT_IN_FRAGMENT) + ZCBOR_ERR_CASE(ZCBOR_ERR_INSIDE_STRING) } #undef ZCBOR_ERR_CASE diff --git a/tests/fuzz/main_entry.c b/tests/fuzz/main_entry.c index cf5ddd11..46c06a71 100644 --- a/tests/fuzz/main_entry.c +++ b/tests/fuzz/main_entry.c @@ -20,7 +20,7 @@ static uint8_t tmp_buffer[AFL_MAX_SIZE]; static size_t afl_read(uint8_t **data) { - ssize_t size = read(0, tmp_buffer, AFL_MAX_SIZE); + ptrdiff_t size = read(0, tmp_buffer, AFL_MAX_SIZE); if (size <= 0) { return 0; } diff --git a/tests/unit/test1_unit_tests/CMakeLists.txt b/tests/unit/test1_unit_tests/CMakeLists.txt index a394559c..4b03bc08 100644 --- a/tests/unit/test1_unit_tests/CMakeLists.txt +++ b/tests/unit/test1_unit_tests/CMakeLists.txt @@ -30,6 +30,7 @@ math(EXPR ZCBOR_VERSION "(${ZCBOR_VERSION_MAJOR} << 24) + (${ZCBOR_VERSION_MINOR zephyr_compile_definitions( ZCBOR_STOP_ON_ERROR + ZCBOR_FRAGMENTS TEST_ZCBOR_VERSION_STR="${ZCBOR_VERSION_STR}" TEST_ZCBOR_VERSION=${ZCBOR_VERSION} TEST_ZCBOR_VERSION_MAJOR=${ZCBOR_VERSION_MAJOR} diff --git a/tests/unit/test1_unit_tests/src/main.c b/tests/unit/test1_unit_tests/src/main.c index c1b16425..61e8a3ed 100644 --- a/tests/unit/test1_unit_tests/src/main.c +++ b/tests/unit/test1_unit_tests/src/main.c @@ -9,6 +9,7 @@ #include "zcbor_encode.h" #include "zcbor_print.h" + ZTEST(zcbor_unit_tests, test_int64) { uint8_t payload[100] = {0}; @@ -409,7 +410,8 @@ ZTEST(zcbor_unit_tests, test_fragments) zassert_false(zcbor_payload_at_end(state_d2), NULL); zassert_false(zcbor_bstr_decode(state_d, &output), NULL); zassert_false(zcbor_payload_at_end(state_d), NULL); - zassert_true(zcbor_bstr_decode_fragment(state_d, &output_frags[0]), NULL); + zassert_true(zcbor_bstr_fragments_start_decode(state_d), NULL); + zcbor_str_fragment_decode(state_d, &output_frags[0]); zassert_equal_ptr(&payload[1], output_frags[0].fragment.value, NULL); zassert_equal(7, output_frags[0].fragment.len, NULL); zassert_equal(10, output_frags[0].total_len, "%d != %d\r\n", 10, output_frags[0].total_len); @@ -418,8 +420,8 @@ ZTEST(zcbor_unit_tests, test_fragments) zassert_true(zcbor_payload_at_end(state_d), NULL); zcbor_update_state(state_d, &payload[8], sizeof(payload) - 8); - zassert_false(zcbor_bstr_decode_fragment(state_d, &output_frags[1]), NULL); - zcbor_next_fragment(state_d, &output_frags[0], &output_frags[1]); + zassert_false(zcbor_bstr_fragments_start_decode(state_d), NULL); + zcbor_str_fragment_decode(state_d, &output_frags[1]); zassert_equal_ptr(&payload[8], output_frags[1].fragment.value, NULL); zassert_equal(3, output_frags[1].fragment.len, "%d != %d\r\n", 3, output_frags[1].fragment.len); zassert_equal(10, output_frags[1].total_len, NULL); @@ -437,7 +439,6 @@ ZTEST(zcbor_unit_tests, test_fragments) zassert_mem_equal(output.value, "HelloWorld", 10, NULL); } - /** The long string "HelloWorld1HelloWorld2..." is split into 18 fragments. * * First, zcbor_validate_string_fragments() is checked to be true, then various @@ -466,14 +467,15 @@ ZTEST(zcbor_unit_tests, test_validate_fragments) ZCBOR_STATE_D(state_d2, 0, payload, sizeof(payload), 1, 0); zassert_true(zcbor_bstr_decode(state_d2, &output), NULL); - zassert_true(zcbor_bstr_decode_fragment(state_d, &output_frags[0]), NULL); + zassert_true(zcbor_bstr_fragments_start_decode(state_d), NULL); + zcbor_str_fragment_decode(state_d, &output_frags[0]); for (int i = 1; i < 18; i++) { zassert_true(zcbor_payload_at_end(state_d), NULL); zassert_false(zcbor_is_last_fragment(&output_frags[i - 1]), NULL); memcpy(frag_payload, &payload[11 * i + 2], 11); // + 2 because of the CBOR header zcbor_update_state(state_d, frag_payload, 11); - zcbor_next_fragment(state_d, &output_frags[i - 1], &output_frags[i]); + zcbor_str_fragment_decode(state_d, &output_frags[i]); } zassert_true(zcbor_payload_at_end(state_d), NULL); zassert_true(zcbor_is_last_fragment(&output_frags[17]), NULL); @@ -535,7 +537,6 @@ ZTEST(zcbor_unit_tests, test_validate_fragments) zassert_true(zcbor_validate_string_fragments(output_frags, 18), NULL); // Check that all errors were restored correctly. } - /** This test creates the following structure, wrapped in a BSTR: * * ( @@ -571,7 +572,6 @@ ZTEST(zcbor_unit_tests, test_bstr_cbor_fragments) uint8_t payload[100]; ZCBOR_STATE_E(state_e, 2, payload, sizeof(payload), 0); struct zcbor_string output; - struct zcbor_string_fragment output_frags[3]; struct zcbor_string_fragment tstr_frags[2]; zassert_true(zcbor_bstr_start_encode(state_e), NULL); // 1 B @@ -594,15 +594,14 @@ ZTEST(zcbor_unit_tests, test_bstr_cbor_fragments) zassert_true(zcbor_bstr_decode(state_d2, &output), NULL); zassert_false(zcbor_bstr_start_decode(state_d, &output), NULL); - zassert_true(zcbor_bstr_start_decode_fragment(state_d, &output_frags[0]), NULL); - zassert_equal_ptr(&payload[1], output_frags[0].fragment.value, NULL); - zassert_equal(7, output_frags[0].fragment.len, NULL); - zassert_equal(EXP_TOTAL_LEN, output_frags[0].total_len, "%d != %d\r\n", EXP_TOTAL_LEN, output_frags[0].total_len); - zassert_equal(0, output_frags[0].offset, NULL); - zassert_false(zcbor_is_last_fragment(&output_frags[0]), NULL); + zassert_true(zcbor_cbor_bstr_fragments_start_decode(state_d), NULL); + zassert_equal_ptr(&payload[0], state_d->constant_state->curr_payload_section, "%p, %p\n",&payload[0], state_d->constant_state->curr_payload_section); + zassert_equal(EXP_TOTAL_LEN, state_d->str_total_len_cbor, "%d != %d\r\n", EXP_TOTAL_LEN, state_d->str_total_len_cbor); + zassert_equal(-1, state_d->frag_offset_cbor, NULL); zassert_true(zcbor_uint32_expect(state_d, 42), NULL); zassert_false(zcbor_tstr_expect_lit(state_d, "Hello World"), NULL); - zassert_true(zcbor_tstr_decode_fragment(state_d, &tstr_frags[0]), NULL); + zassert_true(zcbor_tstr_fragments_start_decode(state_d), NULL); + zassert_true(zcbor_str_fragment_decode(state_d, &tstr_frags[0])); zassert_equal_ptr(&payload[4], tstr_frags[0].fragment.value, NULL); zassert_equal(4, tstr_frags[0].fragment.len, NULL); zassert_equal(11, tstr_frags[0].total_len, NULL); @@ -610,31 +609,23 @@ ZTEST(zcbor_unit_tests, test_bstr_cbor_fragments) zassert_true(zcbor_payload_at_end(state_d), NULL); zcbor_update_state(state_d, &payload[8], 8); - zassert_false(zcbor_bstr_decode_fragment(state_d, &output_frags[1]), NULL); - zcbor_bstr_next_fragment(state_d, &output_frags[0], &output_frags[1]); - zassert_equal_ptr(&payload[8], output_frags[1].fragment.value, NULL); - zassert_equal(8, output_frags[1].fragment.len, "%d != %d\r\n", 3, output_frags[1].fragment.len); - zassert_equal(EXP_TOTAL_LEN, output_frags[1].total_len, "%d != %d\r\n", EXP_TOTAL_LEN, output_frags[1].total_len); - zassert_equal(7, output_frags[1].offset, NULL); - zassert_false(zcbor_is_last_fragment(&output_frags[1]), NULL); - zcbor_next_fragment(state_d, &tstr_frags[0], &tstr_frags[1]); + zassert_true(zcbor_str_fragment_decode(state_d, &tstr_frags[1])); + zassert_true(zcbor_str_fragments_end_decode(state_d)); + zassert_false(zcbor_cbor_bstr_fragments_start_decode(state_d), NULL); zassert_equal_ptr(&payload[8], tstr_frags[1].fragment.value, NULL); zassert_equal(7, tstr_frags[1].fragment.len, "%d != %d\r\n", 7, tstr_frags[1].fragment.len); - zassert_equal(11, tstr_frags[1].total_len, NULL); - zassert_equal(4, tstr_frags[1].offset, NULL); + zassert_equal(11, tstr_frags[1].total_len, "%d != %d\r\n", 11, tstr_frags[1].total_len); + zassert_equal(EXP_TOTAL_LEN, state_d->str_total_len_cbor, "%d != %d\r\n", EXP_TOTAL_LEN, state_d->str_total_len_cbor); + zassert_equal(7, state_d->frag_offset_cbor, NULL); zassert_true(zcbor_is_last_fragment(&tstr_frags[1]), NULL); zassert_true(zcbor_list_start_decode(state_d), NULL); zassert_true(zcbor_payload_at_end(state_d), NULL); zcbor_update_state(state_d, &payload[16], sizeof(payload) - 16); - zassert_false(zcbor_bstr_decode_fragment(state_d, &output_frags[2]), NULL); - zcbor_bstr_next_fragment(state_d, &output_frags[1], &output_frags[2]); - zassert_equal_ptr(&payload[16], output_frags[2].fragment.value, NULL); - zassert_equal(EXP_TOTAL_LEN - 15, - output_frags[2].fragment.len, NULL); - zassert_equal(EXP_TOTAL_LEN, output_frags[2].total_len, NULL); - zassert_equal(15, output_frags[2].offset, NULL); - zassert_true(zcbor_is_last_fragment(&output_frags[2]), NULL); + zassert_false(zcbor_bstr_fragments_start_decode(state_d), NULL); + zassert_equal_ptr(&payload[16], state_d->constant_state->curr_payload_section, NULL); + zassert_equal(EXP_TOTAL_LEN, state_d->str_total_len_cbor, NULL); + zassert_equal(15, state_d->frag_offset_cbor, NULL); zassert_true(zcbor_bool_expect(state_d, true), NULL); zassert_true(zcbor_nil_expect(state_d, NULL), NULL); zassert_true(zcbor_list_end_decode(state_d), NULL); @@ -643,14 +634,6 @@ ZTEST(zcbor_unit_tests, test_bstr_cbor_fragments) output.value = spliced; output.len = sizeof(spliced); - zassert_true(zcbor_validate_string_fragments(output_frags, 3), NULL); - zassert_true(zcbor_splice_string_fragments(output_frags, 3, spliced, &output.len), NULL); - - zassert_equal(EXP_TOTAL_LEN, output.len, NULL); - zassert_mem_equal(output.value, &payload[1], EXP_TOTAL_LEN, NULL); - - output.len = sizeof(spliced); - zassert_true(zcbor_validate_string_fragments(tstr_frags, 2), NULL); zassert_true(zcbor_splice_string_fragments(tstr_frags, 2, spliced, &output.len), NULL); @@ -658,7 +641,6 @@ ZTEST(zcbor_unit_tests, test_bstr_cbor_fragments) zassert_mem_equal(output.value, &payload[4], 11, NULL); } - ZTEST(zcbor_unit_tests, test_canonical_list) { #ifndef ZCBOR_CANONICAL @@ -1011,10 +993,13 @@ ZTEST(zcbor_unit_tests, test_error_str) test_str(ZCBOR_ERR_MAP_FLAGS_NOT_AVAILABLE); test_str(ZCBOR_ERR_INVALID_VALUE_ENCODING); test_str(ZCBOR_ERR_CONSTANT_STATE_MISSING); + test_str(ZCBOR_ERR_INNER_STRING_TOO_LARGE); + test_str(ZCBOR_ERR_NOT_IN_FRAGMENT); + test_str(ZCBOR_ERR_INSIDE_STRING); test_str(ZCBOR_ERR_UNKNOWN); zassert_mem_equal(zcbor_error_str(-1), "ZCBOR_ERR_UNKNOWN", sizeof("ZCBOR_ERR_UNKNOWN"), NULL); zassert_mem_equal(zcbor_error_str(-10), "ZCBOR_ERR_UNKNOWN", sizeof("ZCBOR_ERR_UNKNOWN"), NULL); - zassert_mem_equal(zcbor_error_str(ZCBOR_ERR_CONSTANT_STATE_MISSING + 1), "ZCBOR_ERR_UNKNOWN", sizeof("ZCBOR_ERR_UNKNOWN"), NULL); + zassert_mem_equal(zcbor_error_str(ZCBOR_ERR_INSIDE_STRING + 1), "ZCBOR_ERR_UNKNOWN", sizeof("ZCBOR_ERR_UNKNOWN"), NULL); zassert_mem_equal(zcbor_error_str(100000), "ZCBOR_ERR_UNKNOWN", sizeof("ZCBOR_ERR_UNKNOWN"), NULL); } @@ -1540,5 +1525,4 @@ ZTEST(zcbor_unit_tests, test_remaining_str_len) } - ZTEST_SUITE(zcbor_unit_tests, NULL, NULL, NULL, NULL, NULL);