From 3d66157773d575fb3200641aa8bbcd983213c12c Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 23 Jan 2026 17:22:12 +0100 Subject: [PATCH 1/6] feat: add sentry__value_from_msgpack Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 104 +++++++++++++++ src/sentry_value.h | 10 ++ tests/unit/test_value.c | 273 ++++++++++++++++++++++++++++++++++++++++ tests/unit/tests.inc | 11 ++ 4 files changed, 398 insertions(+) diff --git a/src/sentry_value.c b/src/sentry_value.c index 9891947dc..642449ab3 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1622,3 +1622,107 @@ sentry_event_value_add_stacktrace(sentry_value_t event, void **ips, size_t len) sentry_value_set_stacktrace(thread, ips, len); sentry_event_add_thread(event, thread); } + +static sentry_value_t +value_from_mpack(mpack_node_t node) +{ + switch (mpack_node_type(node)) { + case mpack_type_nil: + return sentry_value_new_null(); + case mpack_type_bool: + return sentry_value_new_bool(mpack_node_bool(node)); + case mpack_type_int: { + int64_t i64_val = mpack_node_i64(node); + if (i64_val >= INT32_MIN && i64_val <= INT32_MAX) { + return sentry_value_new_int32((int32_t)i64_val); + } else { + return sentry_value_new_int64(i64_val); + } + } + case mpack_type_uint: { + uint64_t u64_val = mpack_node_u64(node); + if (u64_val <= INT32_MAX) { + return sentry_value_new_int32((int32_t)u64_val); + } else { + return sentry_value_new_uint64(u64_val); + } + } + case mpack_type_float: + return sentry_value_new_double((double)mpack_node_float(node)); + case mpack_type_double: + return sentry_value_new_double(mpack_node_double(node)); + case mpack_type_str: { + size_t str_len = mpack_node_strlen(node); + return sentry_value_new_string_n(mpack_node_str(node), str_len); + } + case mpack_type_array: { + uint32_t arr_len = mpack_node_array_length(node); + sentry_value_t arr = sentry_value_new_list(); + for (uint32_t i = 0; i < arr_len; i++) { + sentry_value_append( + arr, value_from_mpack(mpack_node_array_at(node, i))); + } + return arr; + } + case mpack_type_map: { + uint32_t map_len = mpack_node_map_count(node); + sentry_value_t obj = sentry_value_new_object(); + for (uint32_t i = 0; i < map_len; i++) { + mpack_node_t key_node = mpack_node_map_key_at(node, i); + if (mpack_node_type(key_node) != mpack_type_str) { + continue; // skip non-string keys + } + mpack_node_t val_node = mpack_node_map_value_at(node, i); + size_t key_len = mpack_node_strlen(key_node); + sentry_value_set_by_key_n(obj, mpack_node_str(key_node), key_len, + value_from_mpack(val_node)); + } + return obj; + } + default: + return sentry_value_new_null(); + } +} + +sentry_value_t +sentry__value_from_msgpack(const char *buf, size_t buf_len) +{ + if (!buf || buf_len == 0) { + return sentry_value_new_null(); + } + + size_t offset = 0; + sentry_value_t result = sentry_value_new_null(); + + while (offset < buf_len) { + mpack_tree_t tree; + mpack_tree_init_data(&tree, buf + offset, buf_len - offset); + mpack_tree_parse(&tree); + + if (mpack_tree_error(&tree) != mpack_ok) { + mpack_tree_destroy(&tree); + break; + } + + size_t size = mpack_tree_size(&tree); + sentry_value_t value = value_from_mpack(mpack_tree_root(&tree)); + mpack_tree_destroy(&tree); + + if (offset == 0 && sentry_value_is_null(result)) { + result = value; + } else { + if (sentry_value_get_type(result) != SENTRY_VALUE_TYPE_LIST) { + sentry_value_t list = sentry_value_new_list(); + if (!sentry_value_is_null(list)) { + sentry_value_append(list, result); + result = list; + } + } + sentry_value_append(result, value); + } + + offset += size; + } + + return result; +} diff --git a/src/sentry_value.h b/src/sentry_value.h index fd277ab39..25b4c8a2f 100644 --- a/src/sentry_value.h +++ b/src/sentry_value.h @@ -107,4 +107,14 @@ int sentry__value_merge_objects(sentry_value_t dst, sentry_value_t src); void sentry__jsonwriter_write_value( sentry_jsonwriter_t *jw, sentry_value_t value); +/** + * Deserialize a sentry value from msgpack. + * + * If the buffer contains multiple sequential msgpack values (as in flat buffers + * like breadcrumb files), they are automatically wrapped in a list. + * + * The returned value must be released with `sentry_value_decref`. + */ +sentry_value_t sentry__value_from_msgpack(const char *buf, size_t buf_len); + #endif diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index fd2d012a9..4a867ee12 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -4,6 +4,7 @@ #include #include #include +#include SENTRY_TEST(value_null) { @@ -1257,3 +1258,275 @@ SENTRY_TEST(event_with_id) sentry_value_decref(event); } + +SENTRY_TEST(value_from_msgpack_empty) +{ + TEST_CHECK(sentry_value_is_null(sentry__value_from_msgpack(NULL, 0))); + TEST_CHECK(sentry_value_is_null(sentry__value_from_msgpack("", 0))); +} + +SENTRY_TEST(value_from_msgpack_null) +{ + sentry_value_t val = sentry_value_new_null(); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_NULL); + TEST_CHECK(sentry_value_is_null(deserialized)); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_bool) +{ + { + sentry_value_t val = sentry_value_new_bool(true); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_BOOL); + TEST_CHECK(sentry_value_is_true(deserialized)); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } + { + sentry_value_t val = sentry_value_new_bool(false); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_BOOL); + TEST_CHECK(!sentry_value_is_true(deserialized)); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } +} + +SENTRY_TEST(value_from_msgpack_int32) +{ + { + sentry_value_t val = sentry_value_new_int32(42); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT32); + TEST_CHECK(sentry_value_as_int32(deserialized) == 42); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } + { + sentry_value_t val = sentry_value_new_int32(-123); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT32); + TEST_CHECK(sentry_value_as_int32(deserialized) == -123); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } +} + +SENTRY_TEST(value_from_msgpack_int64) +{ + { + sentry_value_t val = sentry_value_new_int64((int64_t)INT32_MIN - 1); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT64); + TEST_CHECK( + sentry_value_as_int64(deserialized) == (int64_t)INT32_MIN - 1); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } + { + sentry_value_t val = sentry_value_new_int64(INT64_MIN); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT64); + TEST_CHECK(sentry_value_as_int64(deserialized) == INT64_MIN); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } +} + +SENTRY_TEST(value_from_msgpack_uint64) +{ + sentry_value_t val = sentry_value_new_uint64((uint64_t)INT32_MAX + 1); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_UINT64); + TEST_CHECK(sentry_value_as_uint64(deserialized) == (uint64_t)INT32_MAX + 1); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_double) +{ + sentry_value_t val = sentry_value_new_double(3.14159); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_DOUBLE); + double d = sentry_value_as_double(deserialized); + TEST_CHECK(d > 3.14 && d < 3.15); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_string) +{ + sentry_value_t val = sentry_value_new_string("ล‘รกโ€ฆโ€“๐Ÿคฎ๐Ÿš€ยฟ ํ•œ๊ธ€ ํ…Œ์ŠคํŠธ \a\v"); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_STRING); + TEST_CHECK_STRING_EQUAL( + sentry_value_as_string(deserialized), "ล‘รกโ€ฆโ€“๐Ÿคฎ๐Ÿš€ยฟ ํ•œ๊ธ€ ํ…Œ์ŠคํŠธ \a\v"); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_list) +{ + sentry_value_t inner = sentry_value_new_list(); + sentry_value_append(inner, sentry_value_new_int32(1)); + sentry_value_append(inner, sentry_value_new_int32(2)); + + sentry_value_t val = sentry_value_new_list(); + sentry_value_append(val, inner); + sentry_value_append(val, sentry_value_new_string("outer")); + + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_LIST); + TEST_CHECK(sentry_value_get_length(deserialized) == 2); + + sentry_value_t nested = sentry_value_get_by_index(deserialized, 0); + TEST_CHECK(sentry_value_get_type(nested) == SENTRY_VALUE_TYPE_LIST); + TEST_CHECK(sentry_value_get_length(nested) == 2); + + sentry_value_t nested_elem0 = sentry_value_get_by_index(nested, 0); + TEST_CHECK(sentry_value_as_int32(nested_elem0) == 1); + + sentry_value_t nested_elem1 = sentry_value_get_by_index(nested, 1); + TEST_CHECK(sentry_value_as_int32(nested_elem1) == 2); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_object) +{ + sentry_value_t inner = sentry_value_new_object(); + sentry_value_set_by_key(inner, "x", sentry_value_new_int32(10)); + sentry_value_set_by_key(inner, "y", sentry_value_new_int32(20)); + + sentry_value_t val = sentry_value_new_object(); + sentry_value_set_by_key(val, "position", inner); + sentry_value_set_by_key(val, "label", sentry_value_new_string("point")); + + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_OBJECT); + + sentry_value_t position = sentry_value_get_by_key(deserialized, "position"); + TEST_CHECK(sentry_value_get_type(position) == SENTRY_VALUE_TYPE_OBJECT); + + sentry_value_t x = sentry_value_get_by_key(position, "x"); + TEST_CHECK(sentry_value_as_int32(x) == 10); + + sentry_value_t y = sentry_value_get_by_key(position, "y"); + TEST_CHECK(sentry_value_as_int32(y) == 20); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); +} + +SENTRY_TEST(value_from_msgpack_flat_buffer) +{ + sentry_value_t val1 = sentry_value_new_int32(1); + size_t size1 = 0; + char *buf1 = sentry_value_to_msgpack(val1, &size1); + + sentry_value_t val2 = sentry_value_new_int32(2); + size_t size2 = 0; + char *buf2 = sentry_value_to_msgpack(val2, &size2); + + sentry_value_t val3 = sentry_value_new_string("three"); + size_t size3 = 0; + char *buf3 = sentry_value_to_msgpack(val3, &size3); + + char combined[256]; + size_t combined_size = 0; + memcpy(combined + combined_size, buf1, size1); + combined_size += size1; + memcpy(combined + combined_size, buf2, size2); + combined_size += size2; + memcpy(combined + combined_size, buf3, size3); + combined_size += size3; + + sentry_value_t result = sentry__value_from_msgpack(combined, combined_size); + TEST_CHECK(sentry_value_get_type(result) == SENTRY_VALUE_TYPE_LIST); + TEST_CHECK(sentry_value_get_length(result) == 3); + + sentry_value_t elem0 = sentry_value_get_by_index(result, 0); + TEST_CHECK(sentry_value_as_int32(elem0) == 1); + + sentry_value_t elem1 = sentry_value_get_by_index(result, 1); + TEST_CHECK(sentry_value_as_int32(elem1) == 2); + + sentry_value_t elem2 = sentry_value_get_by_index(result, 2); + TEST_CHECK_STRING_EQUAL(sentry_value_as_string(elem2), "three"); + + sentry_free(buf1); + sentry_free(buf2); + sentry_free(buf3); + sentry_value_decref(val1); + sentry_value_decref(val2); + sentry_value_decref(val3); + sentry_value_decref(result); +} diff --git a/tests/unit/tests.inc b/tests/unit/tests.inc index 43f531a52..a37647166 100644 --- a/tests/unit/tests.inc +++ b/tests/unit/tests.inc @@ -202,6 +202,17 @@ XX(value_attribute) XX(value_bool) XX(value_double) XX(value_freezing) +XX(value_from_msgpack_bool) +XX(value_from_msgpack_double) +XX(value_from_msgpack_empty) +XX(value_from_msgpack_flat_buffer) +XX(value_from_msgpack_int32) +XX(value_from_msgpack_int64) +XX(value_from_msgpack_list) +XX(value_from_msgpack_null) +XX(value_from_msgpack_object) +XX(value_from_msgpack_string) +XX(value_from_msgpack_uint64) XX(value_get_by_null_key) XX(value_int32) XX(value_int64) From ff3a66a78ca37826ad7391191035cf0dfe82dbfe Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 26 Jan 2026 11:11:13 +0100 Subject: [PATCH 2/6] fix: prevent first list value corruption in msgpack parsing When parsing multiple sequential msgpack values where the first value is a list, subsequent values were incorrectly appended directly to that list instead of creating a wrapper list (e.g., [1,2] followed by 3 produced [1,2,3] instead of [[1,2], 3]). Fix by checking on the first iteration if there's more data coming. If so, immediately wrap the first value in a list, ensuring the wrapper list is created upfront when needed. Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 14 ++++++-------- tests/unit/test_value.c | 9 +++++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/sentry_value.c b/src/sentry_value.c index 642449ab3..1f7b98345 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1709,15 +1709,13 @@ sentry__value_from_msgpack(const char *buf, size_t buf_len) mpack_tree_destroy(&tree); if (offset == 0 && sentry_value_is_null(result)) { - result = value; - } else { - if (sentry_value_get_type(result) != SENTRY_VALUE_TYPE_LIST) { - sentry_value_t list = sentry_value_new_list(); - if (!sentry_value_is_null(list)) { - sentry_value_append(list, result); - result = list; - } + if (offset + size < buf_len) { + result = sentry_value_new_list(); + sentry_value_append(result, value); + } else { + result = value; } + } else { sentry_value_append(result, value); } diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 4a867ee12..8e88241c1 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -1488,7 +1488,9 @@ SENTRY_TEST(value_from_msgpack_object) SENTRY_TEST(value_from_msgpack_flat_buffer) { - sentry_value_t val1 = sentry_value_new_int32(1); + sentry_value_t val1 = sentry_value_new_list(); + sentry_value_append(val1, sentry_value_new_int32(1)); + sentry_value_append(val1, sentry_value_new_int32(2)); size_t size1 = 0; char *buf1 = sentry_value_to_msgpack(val1, &size1); @@ -1514,7 +1516,10 @@ SENTRY_TEST(value_from_msgpack_flat_buffer) TEST_CHECK(sentry_value_get_length(result) == 3); sentry_value_t elem0 = sentry_value_get_by_index(result, 0); - TEST_CHECK(sentry_value_as_int32(elem0) == 1); + TEST_CHECK(sentry_value_get_type(elem0) == SENTRY_VALUE_TYPE_LIST); + TEST_CHECK(sentry_value_get_length(elem0) == 2); + TEST_CHECK(sentry_value_as_int32(sentry_value_get_by_index(elem0, 0)) == 1); + TEST_CHECK(sentry_value_as_int32(sentry_value_get_by_index(elem0, 1)) == 2); sentry_value_t elem1 = sentry_value_get_by_index(result, 1); TEST_CHECK(sentry_value_as_int32(elem1) == 2); From c923599912ec17abe3717a46fd6c4160cea4c3c8 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 26 Jan 2026 11:29:20 +0100 Subject: [PATCH 3/6] fix: preserve int64 type for positive values in msgpack deserialization When mpack_write_i64() serializes positive int64 values, it optimizes them using unsigned formats. The deserialization was treating all values above INT32_MAX as uint64, which broke round-trip for signed integers. Now values in range (INT32_MAX, INT64_MAX] deserialize as int64, and only values > INT64_MAX deserialize as uint64. Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 2 ++ tests/unit/test_value.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/sentry_value.c b/src/sentry_value.c index 1f7b98345..080f89809 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1643,6 +1643,8 @@ value_from_mpack(mpack_node_t node) uint64_t u64_val = mpack_node_u64(node); if (u64_val <= INT32_MAX) { return sentry_value_new_int32((int32_t)u64_val); + } else if (u64_val <= INT64_MAX) { + return sentry_value_new_int64((int64_t)u64_val); } else { return sentry_value_new_uint64(u64_val); } diff --git a/tests/unit/test_value.c b/tests/unit/test_value.c index 8e88241c1..8073105e3 100644 --- a/tests/unit/test_value.c +++ b/tests/unit/test_value.c @@ -1371,6 +1371,35 @@ SENTRY_TEST(value_from_msgpack_int64) sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT64); TEST_CHECK(sentry_value_as_int64(deserialized) == INT64_MIN); + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } + { + sentry_value_t val = sentry_value_new_int64((int64_t)INT32_MAX + 1); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT64); + TEST_CHECK( + sentry_value_as_int64(deserialized) == (int64_t)INT32_MAX + 1); + + sentry_free(buf); + sentry_value_decref(val); + sentry_value_decref(deserialized); + } + { + sentry_value_t val = sentry_value_new_int64(INT64_MAX); + size_t size = 0; + char *buf = sentry_value_to_msgpack(val, &size); + + sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); + TEST_CHECK( + sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_INT64); + TEST_CHECK(sentry_value_as_int64(deserialized) == INT64_MAX); + sentry_free(buf); sentry_value_decref(val); sentry_value_decref(deserialized); @@ -1379,13 +1408,13 @@ SENTRY_TEST(value_from_msgpack_int64) SENTRY_TEST(value_from_msgpack_uint64) { - sentry_value_t val = sentry_value_new_uint64((uint64_t)INT32_MAX + 1); + sentry_value_t val = sentry_value_new_uint64(UINT64_MAX); size_t size = 0; char *buf = sentry_value_to_msgpack(val, &size); sentry_value_t deserialized = sentry__value_from_msgpack(buf, size); TEST_CHECK(sentry_value_get_type(deserialized) == SENTRY_VALUE_TYPE_UINT64); - TEST_CHECK(sentry_value_as_uint64(deserialized) == (uint64_t)INT32_MAX + 1); + TEST_CHECK(sentry_value_as_uint64(deserialized) == UINT64_MAX); sentry_free(buf); sentry_value_decref(val); From aa3b537dac2e5bfbc67e576e36dcc88ae13ad7ff Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 26 Jan 2026 12:02:51 +0100 Subject: [PATCH 4/6] fix: use size_t for msgpack array/map iteration to fix MSVC warnings Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sentry_value.c b/src/sentry_value.c index 080f89809..38a2d8ae7 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1658,18 +1658,18 @@ value_from_mpack(mpack_node_t node) return sentry_value_new_string_n(mpack_node_str(node), str_len); } case mpack_type_array: { - uint32_t arr_len = mpack_node_array_length(node); + size_t arr_len = mpack_node_array_length(node); sentry_value_t arr = sentry_value_new_list(); - for (uint32_t i = 0; i < arr_len; i++) { + for (size_t i = 0; i < arr_len; i++) { sentry_value_append( arr, value_from_mpack(mpack_node_array_at(node, i))); } return arr; } case mpack_type_map: { - uint32_t map_len = mpack_node_map_count(node); + size_t map_len = mpack_node_map_count(node); sentry_value_t obj = sentry_value_new_object(); - for (uint32_t i = 0; i < map_len; i++) { + for (size_t i = 0; i < map_len; i++) { mpack_node_t key_node = mpack_node_map_key_at(node, i); if (mpack_node_type(key_node) != mpack_type_str) { continue; // skip non-string keys From ff25bed53ebc1ade7547f06795aafb0096761c72 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 26 Jan 2026 12:04:52 +0100 Subject: [PATCH 5/6] refactor: collapse float/double cases in msgpack deserialization mpack_node_double() handles both types, so no need for separate cases. Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sentry_value.c b/src/sentry_value.c index 38a2d8ae7..4a71a0145 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1650,7 +1650,6 @@ value_from_mpack(mpack_node_t node) } } case mpack_type_float: - return sentry_value_new_double((double)mpack_node_float(node)); case mpack_type_double: return sentry_value_new_double(mpack_node_double(node)); case mpack_type_str: { From 83511fb2fc46c431069d25356a4d8022c551fcdb Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Mon, 26 Jan 2026 12:46:01 +0100 Subject: [PATCH 6/6] fix: handle all mpack_type enum values in switch to fix MSVC warning Add explicit cases for mpack_type_missing and mpack_type_bin to satisfy -Wswitch-enum compiler flag. Co-Authored-By: Claude Opus 4.5 --- src/sentry_value.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sentry_value.c b/src/sentry_value.c index 4a71a0145..adb1b39d5 100644 --- a/src/sentry_value.c +++ b/src/sentry_value.c @@ -1680,6 +1680,8 @@ value_from_mpack(mpack_node_t node) } return obj; } + case mpack_type_missing: + case mpack_type_bin: default: return sentry_value_new_null(); }