diff --git a/debian/libwireshark0.symbols b/debian/libwireshark0.symbols index 40dd889c39..5190a60409 100644 --- a/debian/libwireshark0.symbols +++ b/debian/libwireshark0.symbols @@ -2038,6 +2038,7 @@ libwireshark.so.0 libwireshark0 #MINVER# wscbor_chunk_mark_errors@Base 3.5.1 wscbor_chunk_read@Base 3.5.1 wscbor_error_new@Base 3.5.1 + wscbor_expert_items@Base 3.5.1 wscbor_has_errors@Base 3.5.1 wscbor_init@Base 3.5.1 wscbor_is_indefinite_break@Base 3.5.1 diff --git a/epan/dissectors/packet-cose.c b/epan/dissectors/packet-cose.c index 497b188961..8ba543652b 100644 --- a/epan/dissectors/packet-cose.c +++ b/epan/dissectors/packet-cose.c @@ -369,7 +369,7 @@ static void dissect_header_pair(dissector_table_t dis_table, cose_header_context break; } case CBOR_TYPE_STRING: { - const char *label = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk_label); + const char *label = wscbor_require_tstr(wmem_packet_scope(), chunk_label); item_label = proto_tree_add_cbor_tstr(tree, hf_hdr_label_tstr, pinfo, tvb, chunk_label); if (label) { key.label = ctx->label = @@ -467,7 +467,7 @@ static void dissect_msg_tag(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *t static void dissect_headers(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) { // Protected in bstr wscbor_chunk_t *chunk_prot_bstr = wscbor_chunk_read(wmem_packet_scope(), tvb, offset); - tvbuff_t *tvb_prot = wscbor_require_bstr(tvb, chunk_prot_bstr); + tvbuff_t *tvb_prot = wscbor_require_bstr(wmem_packet_scope(), chunk_prot_bstr); proto_item *item_prot_bstr = proto_tree_add_cbor_bstr(tree, hf_hdr_prot_bstr, pinfo, tvb, chunk_prot_bstr); if (tvb_prot) { proto_tree *tree_prot = proto_item_add_subtree(item_prot_bstr, ett_prot_bstr); @@ -494,13 +494,13 @@ static void dissect_payload(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, proto_tree_add_cbor_ctrl(tree, hf_payload_null, pinfo, tvb, chunk); } else { - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_payload_bstr, pinfo, tvb, chunk); } } static void dissect_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) { wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_signature, pinfo, tvb, chunk); } static void dissect_cose_signature(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) { @@ -521,7 +521,7 @@ static void dissect_ciphertext(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr proto_tree_add_cbor_ctrl(tree, hf_ciphertext_null, pinfo, tvb, chunk); } else { - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_ciphertext_bstr, pinfo, tvb, chunk); } } @@ -557,7 +557,7 @@ static void dissect_cose_recipient(tvbuff_t *tvb, packet_info *pinfo, proto_tree } static void dissect_tag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) { wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_tag, pinfo, tvb, chunk); } @@ -723,7 +723,7 @@ static void dissect_value_alg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre break; } case CBOR_TYPE_STRING: { - const char *val = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk); + const char *val = wscbor_require_tstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_tstr(tree, hf_hdr_alg_tstr, pinfo, tvb, chunk); if (value && val) { *value = g_variant_new_string(val); @@ -739,7 +739,7 @@ static int dissect_header_salt(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tr gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_hdr_salt, pinfo, tvb, chunk); return offset; @@ -831,7 +831,7 @@ static int dissect_header_kid(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_hdr_kid, pinfo, tvb, chunk); return offset; @@ -841,7 +841,7 @@ static int dissect_header_iv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_hdr_iv, pinfo, tvb, chunk); return offset; @@ -851,7 +851,7 @@ static int dissect_header_piv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_hdr_piv, pinfo, tvb, chunk); return offset; @@ -859,7 +859,7 @@ static int dissect_header_piv(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre static void dissect_value_x5cert(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint *offset) { wscbor_chunk_t *chunk_item = wscbor_chunk_read(wmem_packet_scope(), tvb, offset); - tvbuff_t *tvb_item = wscbor_require_bstr(tvb, chunk_item); + tvbuff_t *tvb_item = wscbor_require_bstr(wmem_packet_scope(), chunk_item); if (tvb_item) { // disallow column text rewrite @@ -931,7 +931,7 @@ static int dissect_header_x5t(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre dissect_value_alg(tvb, pinfo, tree_list, &offset, NULL); wscbor_chunk_t *chunk_hash = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk_hash); + wscbor_require_bstr(wmem_packet_scope(), chunk_hash); proto_tree_add_cbor_bstr(tree_list, hf_hdr_x5t_hash, pinfo, tvb, chunk_hash); } @@ -1000,7 +1000,7 @@ static int dissect_keyparam_kty(tvbuff_t *tvb, packet_info *pinfo, proto_tree *t break; } case CBOR_TYPE_STRING: { - const char *val = wscbor_require_tstr(wmem_packet_scope(), tvb, chunk); + const char *val = wscbor_require_tstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_tstr(tree, hf_keyparam_kty_tstr, pinfo, tvb, chunk); if (val) { ctx->principal = g_variant_new_string(val); @@ -1050,7 +1050,7 @@ static int dissect_keyparam_baseiv(tvbuff_t *tvb, packet_info *pinfo, proto_tree gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_keyparam_baseiv, pinfo, tvb, chunk); return offset; @@ -1082,7 +1082,7 @@ static int dissect_keyparam_xcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_keyparam_xcoord, pinfo, tvb, chunk); return offset; @@ -1112,7 +1112,7 @@ static int dissect_keyparam_dcoord(tvbuff_t *tvb, packet_info *pinfo, proto_tree gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_keyparam_dcoord, pinfo, tvb, chunk); return offset; @@ -1122,7 +1122,7 @@ static int dissect_keyparam_k(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tre gint offset = 0; wscbor_chunk_t *chunk = wscbor_chunk_read(wmem_packet_scope(), tvb, &offset); - wscbor_require_bstr(tvb, chunk); + wscbor_require_bstr(wmem_packet_scope(), chunk); proto_tree_add_cbor_bstr(tree, hf_keyparam_k, pinfo, tvb, chunk); return offset; diff --git a/epan/wscbor.c b/epan/wscbor.c index c3022b068c..0edf962041 100644 --- a/epan/wscbor.c +++ b/epan/wscbor.c @@ -26,11 +26,13 @@ static expert_field ei_cbor_invalid = EI_INIT; static expert_field ei_cbor_overflow = EI_INIT; static expert_field ei_cbor_wrong_type = EI_INIT; static expert_field ei_cbor_array_wrong_size = EI_INIT; +static expert_field ei_cbor_indef_string = EI_INIT; static ei_register_info expertitems[] = { {&ei_cbor_invalid, {"_ws.wscbor.cbor_invalid", PI_MALFORMED, PI_ERROR, "CBOR cannot be decoded", EXPFILL}}, {&ei_cbor_overflow, {"_ws.wscbor.cbor_overflow", PI_UNDECODED, PI_ERROR, "CBOR overflow of Wireshark value", EXPFILL}}, {&ei_cbor_wrong_type, {"_ws.wscbor.cbor_wrong_type", PI_MALFORMED, PI_ERROR, "CBOR is wrong type", EXPFILL}}, {&ei_cbor_array_wrong_size, {"_ws.wscbor.array_wrong_size", PI_MALFORMED, PI_WARN, "CBOR array is the wrong size", EXPFILL}}, + {&ei_cbor_indef_string, {"_ws.wscbor.indef_string", PI_COMMENTS_GROUP, PI_COMMENT, "String uses indefinite-length encoding", EXPFILL}}, }; /// The basic header structure of CBOR encoding @@ -81,12 +83,18 @@ static void wscbor_read_unsigned(wscbor_head_t *head, tvbuff_t *tvb) { } /** Read just the CBOR head octet. + * @param alloc The allocator to use. + * @param tvb The TVB to read from. + * @param[in,out] offset The offset with in @c tvb. + * This is updated with just the head length. + * @return The new head object. + * This never returns NULL. * @post Will throw wireshark exception if read fails. */ -static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint start) { +static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset) { wscbor_head_t *head = wmem_new0(alloc, wscbor_head_t); - head->start = start; + head->start = *offset; const guint8 first = tvb_get_guint8(tvb, head->start); head->length += 1; @@ -118,6 +126,7 @@ static wscbor_head_t * wscbor_head_read(wmem_allocator_t *alloc, tvbuff_t *tvb, break; } + *offset += head->length; return head; } @@ -127,21 +136,31 @@ static void wscbor_head_free(wmem_allocator_t *alloc, wscbor_head_t *head) { wmem_free(alloc, head); } +struct _wscbor_chunk_priv_t { + /// The allocator used for wscbor_chunk_t.errors and wscbor_chunk_t.tags + wmem_allocator_t *alloc; + /// For string types, including indefinite length, the item payload. + /// Otherwise NULL. + tvbuff_t *str_value; + +}; + /** Get a clamped string length suitable for tvb functions. - * @param[in,out] chunk The chunk to read and set errors on. + * @param[in,out] chunk The chunk to set errors on. + * @param head_value The value to clamp. * @return The clamped length value. */ -static gint wscbor_get_length(const wscbor_chunk_t *chunk) { +static gint wscbor_get_length(wscbor_chunk_t *chunk, guint64 head_value) { gint length; - if (chunk->head_value > G_MAXINT) { + if (head_value > G_MAXINT) { wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_overflow, + chunk->_priv->alloc, &ei_cbor_overflow, NULL )); length = G_MAXINT; } else { - length = (gint) chunk->head_value; + length = (gint) head_value; } return length; } @@ -168,7 +187,8 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint DISSECTOR_ASSERT(tvb != NULL); wscbor_chunk_t *chunk = wmem_new0(alloc, wscbor_chunk_t); - chunk->_alloc = alloc; + chunk->_priv = wmem_new0(alloc, struct _wscbor_chunk_priv_t); + chunk->_priv->alloc = alloc; chunk->errors = wmem_list_new(alloc); chunk->tags = wmem_list_new(alloc); chunk->start = *offset; @@ -176,8 +196,7 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint // Read a sequence of tags followed by an item header while (TRUE) { // This will break out of the loop if it runs out of buffer - wscbor_head_t *head = wscbor_head_read(alloc, tvb, *offset); - *offset += head->length; + wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset); chunk->head_length += head->length; if (head->error) { wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL)); @@ -198,25 +217,72 @@ wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint chunk->type_minor = head->type_minor; chunk->head_value = head->rawvalue; - chunk->data_length = chunk->head_length; - switch ((cbor_type)(head->type_major)) { - case CBOR_TYPE_BYTESTRING: - case CBOR_TYPE_STRING: - if (chunk->type_minor != 31) { - const gint datalen = wscbor_get_length(chunk); - // skip over definite data - *offset += datalen; - chunk->data_length += datalen; - } - break; - default: - break; - } - wscbor_head_free(alloc, head); break; } + // Data beyond the tags and item head + chunk->data_length = chunk->head_length; + switch (chunk->type_major) { + case CBOR_TYPE_BYTESTRING: + case CBOR_TYPE_STRING: + if (chunk->type_minor != 31) { + const gint datalen = wscbor_get_length(chunk, chunk->head_value); + // skip over definite data + *offset += datalen; + chunk->data_length += datalen; + chunk->_priv->str_value = tvb_new_subset_length(tvb, chunk->start + chunk->head_length, datalen); + } + else { + // indefinite length, sequence of definite items + chunk->_priv->str_value = tvb_new_composite(); + + while (TRUE) { + wscbor_head_t *head = wscbor_head_read(alloc, tvb, offset); + chunk->data_length += head->length; + if (head->error) { + wmem_list_append(chunk->errors, wscbor_error_new(alloc, head->error, NULL)); + } + const gboolean is_break = ( + (head->type_major == CBOR_TYPE_FLOAT_CTRL) + && (head->type_minor == 31) + ); + if (!is_break) { + if (head->type_major != chunk->type_major) { + wmem_list_append(chunk->errors, wscbor_error_new( + chunk->_priv->alloc, &ei_cbor_wrong_type, + "Indefinite sub-string item has major type %d, should be %d", + head->type_major, chunk->type_major + )); + } + else { + const gint datalen = wscbor_get_length(chunk, head->rawvalue); + *offset += datalen; + chunk->data_length += datalen; + tvb_composite_append( + chunk->_priv->str_value, + tvb_new_subset_length(tvb, head->start + head->length, datalen) + ); + } + } + + wscbor_head_free(alloc, head); + if (is_break) { + break; + } + } + + wmem_list_append(chunk->errors, wscbor_error_new( + chunk->_priv->alloc, &ei_cbor_indef_string, + NULL + )); + tvb_composite_finalize(chunk->_priv->str_value); + } + break; + default: + break; + } + return chunk; } @@ -227,7 +293,7 @@ static void wscbor_subitem_free(gpointer data, gpointer userdata) { void wscbor_chunk_free(wscbor_chunk_t *chunk) { DISSECTOR_ASSERT(chunk); - wmem_allocator_t *alloc = chunk->_alloc; + wmem_allocator_t *alloc = chunk->_priv->alloc; wmem_list_foreach(chunk->errors, wscbor_subitem_free, alloc); wmem_destroy_list(chunk->errors); wmem_list_foreach(chunk->tags, wscbor_subitem_free, alloc); @@ -270,11 +336,7 @@ gboolean wscbor_skip_next_item(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *off break; case CBOR_TYPE_BYTESTRING: case CBOR_TYPE_STRING: - if (chunk->type_minor == 31) { - // wait for indefinite break - while (!wscbor_skip_next_item(alloc, tvb, offset)) {} - } - // wscbor_read_chunk() sets offset past definite value + // wscbor_read_chunk() sets offset past string value break; case CBOR_TYPE_ARRAY: { if (chunk->type_minor == 31) { @@ -334,12 +396,19 @@ void wscbor_init(void) { expert_register_field_array(expert_wscbor, expertitems, array_length(expertitems)); } +const ei_register_info * wscbor_expert_items(int *size) { + if (size) { + *size = array_length(expertitems); + } + return expertitems; +} + gboolean wscbor_require_major_type(wscbor_chunk_t *chunk, cbor_type major) { if (chunk->type_major == major) { return TRUE; } wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_wrong_type, + chunk->_priv->alloc, &ei_cbor_wrong_type, "Item has major type %d, should be %d", chunk->type_major, major )); @@ -356,7 +425,7 @@ gboolean wscbor_require_array_size(wscbor_chunk_t *chunk, guint64 count_min, gui } if ((chunk->head_value < count_min) || (chunk->head_value > count_max)) { wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_array_wrong_size, + chunk->_priv->alloc, &ei_cbor_array_wrong_size, "Array has %" PRId64 " items, should be within [%"PRId64", %"PRId64"]", chunk->head_value, count_min, count_max )); @@ -384,7 +453,7 @@ gboolean * wscbor_require_boolean(wmem_allocator_t *alloc, wscbor_chunk_t *chunk } default: wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_wrong_type, + chunk->_priv->alloc, &ei_cbor_wrong_type, "Item has minor type %d, should be %d or %d", chunk->type_minor, CBOR_CTRL_TRUE, CBOR_CTRL_FALSE )); @@ -412,7 +481,7 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) { if (chunk->head_value > INT64_MAX) { clamped = INT64_MAX; wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_overflow, + chunk->_priv->alloc, &ei_cbor_overflow, NULL )); } @@ -431,7 +500,7 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) { } default: wmem_list_append(chunk->errors, wscbor_error_new( - chunk->_alloc, &ei_cbor_wrong_type, + chunk->_priv->alloc, &ei_cbor_wrong_type, "Item has major type %d, should be %d or %d", chunk->type_major, CBOR_TYPE_UINT, CBOR_TYPE_NEGINT )); @@ -440,20 +509,20 @@ gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) { return result; } -char * wscbor_require_tstr(wmem_allocator_t *alloc, tvbuff_t *parent, wscbor_chunk_t *chunk) { +char * wscbor_require_tstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk) { if (!wscbor_require_major_type(chunk, CBOR_TYPE_STRING)) { return NULL; } - return (char *)tvb_get_string_enc(alloc, parent, chunk->start + chunk->head_length, wscbor_get_length(chunk), ENC_UTF_8); + return (char *)tvb_get_string_enc(alloc, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), ENC_UTF_8); } -tvbuff_t * wscbor_require_bstr(tvbuff_t *parent, wscbor_chunk_t *chunk) { +tvbuff_t * wscbor_require_bstr(wmem_allocator_t *alloc _U_, wscbor_chunk_t *chunk) { if (!wscbor_require_major_type(chunk, CBOR_TYPE_BYTESTRING)) { return NULL; } - return tvb_new_subset_length(parent, chunk->start + chunk->head_length, wscbor_get_length(chunk)); + return chunk->_priv->str_value; } proto_item * proto_tree_add_cbor_container(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) { @@ -533,14 +602,14 @@ proto_item * proto_tree_add_cbor_bitmask(proto_tree *tree, int hfindex, const gi return item; } -proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) { - proto_item *item = proto_tree_add_item(tree, hfindex, tvb, chunk->start + chunk->head_length, wscbor_get_length(chunk), 0); +proto_item * proto_tree_add_cbor_tstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) { + proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0); wscbor_chunk_mark_errors(pinfo, item, chunk); return item; } -proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb, const wscbor_chunk_t *chunk) { - proto_item *item = proto_tree_add_item(tree, hfindex, tvb, chunk->start + chunk->head_length, wscbor_get_length(chunk), 0); +proto_item * proto_tree_add_cbor_bstr(proto_tree *tree, int hfindex, packet_info *pinfo, tvbuff_t *tvb _U_, const wscbor_chunk_t *chunk) { + proto_item *item = proto_tree_add_item(tree, hfindex, chunk->_priv->str_value, 0, tvb_reported_length(chunk->_priv->str_value), 0); wscbor_chunk_mark_errors(pinfo, item, chunk); return item; } diff --git a/epan/wscbor.h b/epan/wscbor.h index 0687afaff5..43bad16905 100644 --- a/epan/wscbor.h +++ b/epan/wscbor.h @@ -30,6 +30,13 @@ extern "C" { WS_DLL_PUBLIC void wscbor_init(void); +/** Expose available expert info for this library. + * @param[out] size Set to the size of the array. + * @return The array of expert info objects. + */ +WS_DLL_PUBLIC +const ei_register_info * wscbor_expert_items(int *size); + /// The same enumeration from libcbor-0.5 typedef enum cbor_type { CBOR_TYPE_UINT = 0, ///< positive integers @@ -79,10 +86,12 @@ typedef struct { guint64 value; } wscbor_tag_t; +struct _wscbor_chunk_priv_t; +typedef struct _wscbor_chunk_priv_t wscbor_chunk_priv_t; /// A data-containing, optionally-tagged chunk of CBOR typedef struct { - /// The allocator used for #errors and #tags - wmem_allocator_t *_alloc; + /// Internal private data + wscbor_chunk_priv_t *_priv; /// The start offset of this chunk gint start; @@ -111,9 +120,11 @@ typedef struct { * @param alloc The allocator to use. * @param tvb The TVB to read from. * @param[in,out] offset The offset with in @c tvb. + * This is updated to be just past the new chunk. * @return The chunk of data found, including any errors. * This never returns NULL. - * @post This can throw ReportedBoundsError if the read itself ran out of data. + * @post This can throw ReportedBoundsError or ContainedBoundsError + * if the read itself ran out of data. */ WS_DLL_PUBLIC wscbor_chunk_t * wscbor_chunk_read(wmem_allocator_t *alloc, tvbuff_t *tvb, gint *offset); @@ -239,24 +250,30 @@ WS_DLL_PUBLIC gint64 * wscbor_require_int64(wmem_allocator_t *alloc, wscbor_chunk_t *chunk); /** Require a CBOR item to have a text-string value. + * If the actual text string is not needed, use the following to avoid an + * unnecessary allocation. + * @code + * wscbor_require_major_type(chunk, CBOR_TYPE_STRING) + * @endcode * * @param alloc The allocator to use. - * @param parent The containing buffer. * @param[in,out] chunk The chunk to read from and write errors on. * @return Pointer to the null-terminated UTF-8, if the item was a tstr. + * @post This can throw ContainedBoundsError string ran out of data. */ WS_DLL_PUBLIC -char * wscbor_require_tstr(wmem_allocator_t *alloc, tvbuff_t *parent, wscbor_chunk_t *chunk); +char * wscbor_require_tstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk); /** Require a CBOR item to have a byte-string value. + * Use tvb_memdup() or similar if the raw byte-string is needed. * - * @param parent The containing buffer. + * @param alloc The allocator to use. * @param[in,out] chunk The chunk to read from and write errors on. - * @return Pointer to the value, if the item was an string. + * @return Pointer to the value, if the item was an bstr. * The value is memory managed by wireshark. */ WS_DLL_PUBLIC -tvbuff_t * wscbor_require_bstr(tvbuff_t *parent, wscbor_chunk_t *chunk); +tvbuff_t * wscbor_require_bstr(wmem_allocator_t *alloc, wscbor_chunk_t *chunk); /** Add an item representing an array or map container. * If the item is type FT_UINT* or FT_INT* the count of (array) items diff --git a/epan/wscbor_test.c b/epan/wscbor_test.c index e0952204b5..ce66c6ec1a 100644 --- a/epan/wscbor_test.c +++ b/epan/wscbor_test.c @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -41,7 +42,9 @@ DIAG_OFF_PEDANTIC example_s ex_uint = {1, (const guint8 *)"\x01", 1, 1, CBOR_TYPE_UINT, 1}; example_s ex_nint = {1, (const guint8 *)"\x20", 1, 1, CBOR_TYPE_NEGINT, 0}; example_s ex_bstr = {3, (const guint8 *)"\x42\x68\x69", 1, 3, CBOR_TYPE_BYTESTRING, 2}; +example_s ex_bstr_indef = {6, (const guint8 *)"\x5F\x41\x68\x41\x69\xFF", 1, 6, CBOR_TYPE_BYTESTRING, 0}; example_s ex_tstr = {3, (const guint8 *)"\x62\x68\x69", 1, 3, CBOR_TYPE_STRING, 2}; +example_s ex_tstr_indef = {6, (const guint8 *)"\x7F\x61\x68\x61\x69\xFF", 1, 6, CBOR_TYPE_STRING, 0}; example_s ex_false = {1, (const guint8 *)"\xF4", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_FALSE}; example_s ex_true = {1, (const guint8 *)"\xF5", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_TRUE}; example_s ex_null = {1, (const guint8 *)"\xF6", 1, 1, CBOR_TYPE_FLOAT_CTRL, CBOR_CTRL_NULL}; @@ -57,10 +60,25 @@ DIAG_ON_PEDANTIC static const example_s * all_examples[] = { &ex_uint, &ex_nint, - &ex_bstr, &ex_bstr_short, &ex_tstr, + &ex_bstr, &ex_bstr_indef, + &ex_tstr, &ex_tstr_indef, &ex_false, &ex_true, &ex_null, &ex_undef, &ex_break }; +static wmem_map_t *real_errors = NULL; + +static gint has_real_errors(const wscbor_chunk_t *chunk) { + gint count = 0; + wmem_list_frame_t *frm = wmem_list_head(chunk->errors); + for (; frm; frm = wmem_list_frame_next(frm)) { + const wscbor_error_t *err = wmem_list_frame_data(frm); + if (wmem_map_contains(real_errors, err->ei)) { + count += 1; + } + } + return count; +} + /* * These test are organized in order of the appearance, in wscbor.h, of * the basic functions that they test. This makes it easier to @@ -71,7 +89,7 @@ static const example_s * all_examples[] = { /* WSCBOR TESTING FUNCTIONS (/wscbor/) */ static void -wscbor_test_read_simple(void) +wscbor_test_chunk_read_simple(void) { for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { const example_s *ex = all_examples[ex_ix]; @@ -82,7 +100,7 @@ wscbor_test_read_simple(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpuint(chunk->head_length, ==, ex->head_length); g_assert_cmpuint(chunk->data_length, ==, ex->data_length); @@ -96,7 +114,7 @@ wscbor_test_read_simple(void) } static void -wscbor_test_read_simple_tags(void) +wscbor_test_chunk_read_simple_tags(void) { const guint8 *const tags = (const guint8 *)"\xC1\xD8\xC8"; tvbuff_t *tvb_tags = tvb_new_real_data(tags, 3, 3); @@ -114,7 +132,7 @@ wscbor_test_read_simple_tags(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpuint(chunk->head_length, ==, ex->head_length + 3); g_assert_cmpuint(chunk->data_length, ==, ex->data_length + 3); @@ -146,7 +164,7 @@ wscbor_test_read_simple_tags(void) } static void -wscbor_test_read_invalid(void) +wscbor_test_chunk_read_invalid(void) { tvbuff_t *tvb = tvb_new_real_data((const guint8 *)"\x00\x01\x02\xC1", 4, 2); gint offset = 2; @@ -154,33 +172,33 @@ wscbor_test_read_invalid(void) { // last valid item wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpuint(chunk->type_major, ==, CBOR_TYPE_UINT); g_assert_cmpuint(chunk->head_value, ==, 2); wscbor_chunk_free(chunk); } g_assert_cmpint(offset, ==, 3); { // Tag without item - guint caught = 0; + volatile gulong caught = 0; TRY { wscbor_chunk_read(test_scope, tvb, &offset); g_assert(FALSE); } - CATCH(ReportedBoundsError) { - caught = ReportedBoundsError; + CATCH_BOUNDS_ERRORS { + caught = exc->except_id.except_code; } ENDTRY; g_assert_cmpuint(caught, ==, ReportedBoundsError); } g_assert_cmpint(offset, ==, 4); { // Read past the end - volatile guint caught = 0; + volatile gulong caught = 0; TRY { wscbor_chunk_read(test_scope, tvb, &offset); g_assert(FALSE); } - CATCH(ReportedBoundsError) { - caught = ReportedBoundsError; + CATCH_BOUNDS_ERRORS { + caught = exc->except_id.except_code; } ENDTRY; g_assert_cmpuint(caught, ==, ReportedBoundsError); @@ -202,17 +220,17 @@ wscbor_test_is_indefinite_break(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); // this test never modifies the chunk const gboolean val = wscbor_is_indefinite_break(chunk); if (memcmp(ex->enc, "\xFF", 1) == 0) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); } wscbor_chunk_free(chunk); @@ -221,22 +239,44 @@ wscbor_test_is_indefinite_break(void) } static void -wscbor_test_skip_next_item(void) +wscbor_test_skip_next_item_simple(void) +{ + // skip simple items + for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { + const example_s *ex = all_examples[ex_ix]; + printf("simple #%zu\n", ex_ix); + + tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len); + gint offset = 0; + wscbor_skip_next_item(test_scope, tvb, &offset); + g_assert_cmpint(offset, ==, ex->data_length); + + tvb_free(tvb); + } +} + +static void +wscbor_test_skip_next_item_multiple(void) { tvbuff_t *tvb = tvb_new_real_data((const guint8 *)"\x00\x01\x02\x03", 4, 4); - gint offset = 3; + gint offset = 2; + gboolean res = wscbor_skip_next_item(test_scope, tvb, &offset); g_assert(!res); + g_assert_cmpint(offset, ==, 3); + + res = wscbor_skip_next_item(test_scope, tvb, &offset); + g_assert(!res); g_assert_cmpint(offset, ==, 4); { // Read past the end - guint caught = 0; + volatile gulong caught = 0; TRY { wscbor_skip_next_item(test_scope, tvb, &offset); g_assert(FALSE); } - CATCH(ReportedBoundsError) { - caught = ReportedBoundsError; + CATCH_BOUNDS_ERRORS { + caught = exc->except_id.except_code; } ENDTRY; g_assert_cmpuint(caught, ==, ReportedBoundsError); @@ -258,14 +298,14 @@ wscbor_test_require_major_type(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert(wscbor_require_major_type(chunk, ex->type_major)); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); // any other type g_assert(!wscbor_require_major_type(chunk, ex->type_major + 1)); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); wscbor_chunk_free(chunk); tvb_free(tvb); @@ -273,7 +313,7 @@ wscbor_test_require_major_type(void) } static void -wscbor_test_require_boolean(void) +wscbor_test_require_boolean_simple(void) { for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { const example_s *ex = all_examples[ex_ix]; @@ -284,18 +324,18 @@ wscbor_test_require_boolean(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); const gboolean *val = wscbor_require_boolean(test_scope, chunk); if ((ex->type_major == CBOR_TYPE_FLOAT_CTRL) && ((ex->head_value == CBOR_CTRL_FALSE) || (ex->head_value == CBOR_CTRL_TRUE))) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpint(*val, ==, ex->head_value == CBOR_CTRL_TRUE); } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); } wscbor_chunk_free(chunk); @@ -304,7 +344,7 @@ wscbor_test_require_boolean(void) } static void -wscbor_test_require_int64(void) +wscbor_test_require_int64_simple(void) { for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { const example_s *ex = all_examples[ex_ix]; @@ -315,22 +355,22 @@ wscbor_test_require_int64(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); const gint64 *val = wscbor_require_int64(test_scope, chunk); if (ex->type_major == CBOR_TYPE_UINT) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpint(*val, ==, ex->head_value); } else if (ex->type_major == CBOR_TYPE_NEGINT) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpint(*val, ==, -1 - ex->head_value); } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); } wscbor_chunk_free(chunk); @@ -353,24 +393,24 @@ wscbor_test_require_int64_overflow(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpuint(chunk->type_major, ==, ex->type_major); g_assert_cmpuint(chunk->head_value, ==, ex->head_value); const gint64 *val = wscbor_require_int64(test_scope, chunk); if (ex->type_major == CBOR_TYPE_UINT) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); g_assert_cmpint(*val, ==, G_MAXINT64); } else if (ex->type_major == CBOR_TYPE_NEGINT) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); g_assert_cmpint(*val, ==, G_MININT64); } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); } wscbor_chunk_free(chunk); @@ -379,7 +419,7 @@ wscbor_test_require_int64_overflow(void) } static void -wscbor_test_require_tstr(void) +wscbor_test_require_tstr_simple(void) { for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { const example_s *ex = all_examples[ex_ix]; @@ -390,18 +430,20 @@ wscbor_test_require_tstr(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); - const char *val = wscbor_require_tstr(test_scope, tvb, chunk); + const char *val = wscbor_require_tstr(test_scope, chunk); if (ex->type_major == CBOR_TYPE_STRING) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); - // only works because this is Latin-1 text - g_assert_cmpint(strlen(val), ==, ex->head_value); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); + if (ex->head_value > 0) { + // only works because this is Latin-1 text + g_assert_cmpmem(val, strlen(val), ex->enc + ex->head_length, ex->head_value); + } } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); } wscbor_chunk_free(chunk); @@ -427,20 +469,20 @@ wscbor_test_require_tstr_short(void) chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); g_assert_cmpuint(chunk->type_major, ==, ex->type_major); g_assert_cmpuint(chunk->head_value, ==, ex->head_value); - volatile guint caught = 0; + volatile gulong caught = 0; TRY { - wscbor_require_tstr(test_scope, tvb, chunk); + wscbor_require_tstr(test_scope, chunk); g_assert(FALSE); } - CATCH(ReportedBoundsError) { - caught = ReportedBoundsError; + CATCH_BOUNDS_ERRORS { + caught = exc->except_id.except_code; } ENDTRY; - g_assert_cmpuint(caught, ==, ReportedBoundsError); + g_assert_cmpuint(caught, ==, ContainedBoundsError); wscbor_chunk_free(chunk); tvb_free(tvb); @@ -448,7 +490,7 @@ wscbor_test_require_tstr_short(void) } static void -wscbor_test_require_bstr(void) +wscbor_test_require_bstr_simple(void) { for (size_t ex_ix = 0; ex_ix < (sizeof(all_examples) / sizeof(example_s*)); ++ex_ix) { const example_s *ex = all_examples[ex_ix]; @@ -459,18 +501,25 @@ wscbor_test_require_bstr(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); - const tvbuff_t *val = wscbor_require_bstr(tvb, chunk); + tvbuff_t *val = wscbor_require_bstr(test_scope, chunk); if (ex->type_major == CBOR_TYPE_BYTESTRING) { g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 0); - g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value); - g_assert_cmpuint(tvb_captured_length(val), <=, ex->head_value); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); + if (ex->head_value > 0) { + g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value); + g_assert_cmpuint(tvb_captured_length(val), ==, ex->head_value); + + const gint buflen = tvb_reported_length(val); + void *buf = tvb_memdup(test_scope, val, 0, buflen); + g_assert(buf); + g_assert_cmpmem(buf, buflen, ex->enc + ex->head_length, ex->head_value); + } } else { g_assert(!val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); } wscbor_chunk_free(chunk); @@ -478,6 +527,49 @@ wscbor_test_require_bstr(void) } } +static void +wscbor_test_require_bstr_short(void) +{ + const example_s * examples[] = { + &ex_bstr_short, + }; + for (size_t ex_ix = 0; ex_ix < (sizeof(examples) / sizeof(example_s*)); ++ex_ix) { + const example_s *ex = examples[ex_ix]; + printf("simple #%zu\n", ex_ix); + + tvbuff_t *tvb = tvb_new_real_data(ex->enc, ex->enc_len, ex->enc_len); + gint offset = 0; + + wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); + g_assert(chunk); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); + g_assert_cmpuint(chunk->type_major, ==, ex->type_major); + g_assert_cmpuint(chunk->head_value, ==, ex->head_value); + + // no exception, but truncated captured length + tvbuff_t *val = wscbor_require_bstr(test_scope, chunk); + g_assert(val); + g_assert_cmpuint(has_real_errors(chunk), ==, 0); + g_assert_cmpint(tvb_reported_length(val), ==, ex->head_value); + g_assert_cmpuint(tvb_captured_length(val), <, ex->head_value); + + volatile gulong caught = 0; + TRY { + const gint buflen = tvb_reported_length(val); + tvb_memdup(test_scope, val, 0, buflen); + g_assert(FALSE); + } + CATCH_BOUNDS_ERRORS { + caught = exc->except_id.except_code; + } + ENDTRY; + g_assert_cmpuint(caught, ==, ContainedBoundsError); + + wscbor_chunk_free(chunk); + tvb_free(tvb); + } +} + static void wscbor_test_require_bstr_overflow(void) { @@ -493,13 +585,13 @@ wscbor_test_require_bstr_overflow(void) wscbor_chunk_t *chunk = wscbor_chunk_read(test_scope, tvb, &offset); g_assert(chunk); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 1); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); g_assert_cmpuint(chunk->type_major, ==, ex->type_major); g_assert_cmpuint(chunk->head_value, ==, ex->head_value); - const tvbuff_t *val = wscbor_require_bstr(tvb, chunk); + const tvbuff_t *val = wscbor_require_bstr(test_scope, chunk); g_assert(val); - g_assert_cmpuint(wscbor_has_errors(chunk), ==, 2); + g_assert_cmpuint(has_real_errors(chunk), ==, 1); g_assert_cmpuint(tvb_reported_length(val), ==, G_MAXINT); g_assert_cmpuint(tvb_captured_length(val), ==, 2); @@ -515,22 +607,35 @@ main(int argc, char **argv) g_test_init(&argc, &argv, NULL); - g_test_add_func("/wscbor/read/simple", wscbor_test_read_simple); - g_test_add_func("/wscbor/read/simple_tags", wscbor_test_read_simple_tags); - g_test_add_func("/wscbor/read/invalid", wscbor_test_read_invalid); + g_test_add_func("/wscbor/chunk_read/simple", wscbor_test_chunk_read_simple); + g_test_add_func("/wscbor/chunk_read/simple_tags", wscbor_test_chunk_read_simple_tags); + g_test_add_func("/wscbor/chunk_read/invalid", wscbor_test_chunk_read_invalid); g_test_add_func("/wscbor/is_indefinite_break", wscbor_test_is_indefinite_break); - g_test_add_func("/wscbor/skip_next_item", wscbor_test_skip_next_item); + g_test_add_func("/wscbor/skip_next_item/simple", wscbor_test_skip_next_item_simple); + g_test_add_func("/wscbor/skip_next_item/multiple", wscbor_test_skip_next_item_multiple); g_test_add_func("/wscbor/require_major_type", wscbor_test_require_major_type); - g_test_add_func("/wscbor/require_boolean", wscbor_test_require_boolean); - g_test_add_func("/wscbor/require_int64", wscbor_test_require_int64); - g_test_add_func("/wscbor/require_int64_overflow", wscbor_test_require_int64_overflow); - g_test_add_func("/wscbor/require_tstr", wscbor_test_require_tstr); - g_test_add_func("/wscbor/require_tstr_short", wscbor_test_require_tstr_short); - g_test_add_func("/wscbor/require_bstr", wscbor_test_require_bstr); - g_test_add_func("/wscbor/require_bstr_overflow", wscbor_test_require_bstr_overflow); + g_test_add_func("/wscbor/require_boolean/simple", wscbor_test_require_boolean_simple); + g_test_add_func("/wscbor/require_int64/simple", wscbor_test_require_int64_simple); + g_test_add_func("/wscbor/require_int64/overflow", wscbor_test_require_int64_overflow); + g_test_add_func("/wscbor/require_tstr/simple", wscbor_test_require_tstr_simple); + g_test_add_func("/wscbor/require_tstr/short", wscbor_test_require_tstr_short); + g_test_add_func("/wscbor/require_bstr/simple", wscbor_test_require_bstr_simple); + g_test_add_func("/wscbor/require_bstr/short", wscbor_test_require_bstr_short); + g_test_add_func("/wscbor/require_bstr/overflow", wscbor_test_require_bstr_overflow); wmem_init_scopes(); test_scope = wmem_allocator_new(WMEM_ALLOCATOR_STRICT); + { + // Extract high-severity errors + int ex_size = 0; + const ei_register_info *ex_items = wscbor_expert_items(&ex_size); + real_errors = wmem_map_new(test_scope, g_direct_hash, g_direct_equal); + for (int ix = 0; ix < ex_size; ++ix) { + if (ex_items[ix].eiinfo.severity & (PI_NOTE|PI_WARN|PI_ERROR)) { + wmem_map_insert(real_errors, ex_items[ix].ids, NULL); + } + } + } //cannot use: wscbor_init(); result = g_test_run(); //none needed: wscbor_cleanup();