diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b664b289..7aa9e0df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +# 2026-09-05 version 7.0.3 + * Fix ext32 unpacking of the maximum UINT32_MAX-byte payload. (#1185) + # 2026-08-25 version 7.0.2 * Fix integer overflow on msgpack_unpacker_expand_buffer(). (#1182) diff --git a/README.md b/README.md index 63a5038b1..a4951cac8 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ `msgpack` for C =================== -Version 7.0.2 [![Build Status](https://github.com/msgpack/msgpack-c/workflows/CI/badge.svg?branch=c_master)](https://github.com/msgpack/msgpack-c/actions) [![Build status](https://ci.appveyor.com/api/projects/status/8kstcgt79qj123mw/branch/c_master?svg=true)](https://ci.appveyor.com/project/redboltz/msgpack-c/branch/c_master) +Version 7.0.3 [![Build Status](https://github.com/msgpack/msgpack-c/workflows/CI/badge.svg?branch=c_master)](https://github.com/msgpack/msgpack-c/actions) [![Build status](https://ci.appveyor.com/api/projects/status/8kstcgt79qj123mw/branch/c_master?svg=true)](https://ci.appveyor.com/project/redboltz/msgpack-c/branch/c_master) [![codecov](https://codecov.io/gh/msgpack/msgpack-c/branch/c_master/graph/badge.svg)](https://app.codecov.io/gh/msgpack/msgpack-c/tree/c_master) It's like JSON but smaller and faster. diff --git a/appveyor.yml b/appveyor.yml index cc316d5bc..fe708c998 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 7.0.2.{build} +version: 7.0.3.{build} branches: only: diff --git a/include/msgpack/unpack_template.h b/include/msgpack/unpack_template.h index de30f3cf0..e0a37ffa9 100644 --- a/include/msgpack/unpack_template.h +++ b/include/msgpack/unpack_template.h @@ -53,7 +53,7 @@ msgpack_unpack_struct_decl(_stack) { msgpack_unpack_struct_decl(_context) { msgpack_unpack_user user; unsigned int cs; - unsigned int trail; + size_t trail; unsigned int top; /* msgpack_unpack_struct(_stack)* stack; @@ -99,7 +99,7 @@ msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const c const unsigned char* const pe = (unsigned char*)data + len; const void* n = NULL; - unsigned int trail = ctx->trail; + size_t trail = ctx->trail; unsigned int cs = ctx->cs; unsigned int top = ctx->top; msgpack_unpack_struct(_stack)* stack = ctx->stack; @@ -326,7 +326,7 @@ msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const c case MSGPACK_CS_EXT_16:{ uint16_t tmp; _msgpack_load16(uint16_t,n,&tmp); - again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); + again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, (size_t)tmp + 1, _ext_zero); } case MSGPACK_CS_STR_32:{ uint32_t tmp; @@ -341,7 +341,11 @@ msgpack_unpack_func(int, _execute)(msgpack_unpack_struct(_context)* ctx, const c case MSGPACK_CS_EXT_32:{ uint32_t tmp; _msgpack_load32(uint32_t,n,&tmp); - again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, tmp + 1, _ext_zero); + /* cast before adding: on a 64-bit size_t this lets an ext32 with + * the maximum UINT32_MAX-byte payload carry its trailing type + * byte without wrapping trail back to 0 the way `tmp + 1` would + * when tmp is exactly UINT32_MAX */ + again_fixed_trail_if_zero(MSGPACK_ACS_EXT_VALUE, (size_t)tmp + 1, _ext_zero); } case MSGPACK_ACS_STR_VALUE: _str_zero: diff --git a/include/msgpack/version_master.h b/include/msgpack/version_master.h index ad4460965..0e0b621c7 100644 --- a/include/msgpack/version_master.h +++ b/include/msgpack/version_master.h @@ -1,3 +1,3 @@ #define MSGPACK_VERSION_MAJOR 7 #define MSGPACK_VERSION_MINOR 0 -#define MSGPACK_VERSION_REVISION 2 +#define MSGPACK_VERSION_REVISION 3 diff --git a/src/unpack.c b/src/unpack.c index 2d02a721c..0b1f516e8 100644 --- a/src/unpack.c +++ b/src/unpack.c @@ -275,7 +275,7 @@ static inline int template_callback_map_item(unpack_user* u, msgpack_object* c, return 0; } -static inline int template_callback_str(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) +static inline int template_callback_str(unpack_user* u, const char* b, const char* p, size_t l, msgpack_object* o) { MSGPACK_UNUSED(b); if (*u->z == NULL) { @@ -291,7 +291,7 @@ static inline int template_callback_str(unpack_user* u, const char* b, const cha return 0; } -static inline int template_callback_bin(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) +static inline int template_callback_bin(unpack_user* u, const char* b, const char* p, size_t l, msgpack_object* o) { MSGPACK_UNUSED(b); if (*u->z == NULL) { @@ -307,7 +307,7 @@ static inline int template_callback_bin(unpack_user* u, const char* b, const cha return 0; } -static inline int template_callback_ext(unpack_user* u, const char* b, const char* p, unsigned int l, msgpack_object* o) +static inline int template_callback_ext(unpack_user* u, const char* b, const char* p, size_t l, msgpack_object* o) { MSGPACK_UNUSED(b); if (l == 0) { diff --git a/test/msgpack_c.cpp b/test/msgpack_c.cpp index 5a062b63f..572441b01 100644 --- a/test/msgpack_c.cpp +++ b/test/msgpack_c.cpp @@ -642,6 +642,45 @@ TEST(MSGPACKC, simple_buffer_fixext_4byte_65536) msgpack_sbuffer_destroy(&sbuf); } +// ext32's length header covers up to UINT32_MAX bytes of data. The packed +// message (header + body) does not fit in a 32-bit size_t, so this test is +// only built for 64-bit targets. On 32-bit builds gcc also rejects the +// UINT32_MAX-sized calloc()/memcmp() under -Werror. +#if SIZE_MAX > UINT32_MAX +TEST(MSGPACKC, simple_buffer_ext_maxlen) +{ + // Needs roughly 8GB of free memory (the source buffer plus the packed + // copy). If the allocation fails, pass vacuously instead of failing. + // (GTEST_SKIP() is not used because it requires googletest >= 1.10.) + const size_t size = static_cast(UINT32_MAX); + void* buf = calloc(size, 1); + if (buf == NULL) { + return; + } + + msgpack_sbuffer sbuf; + msgpack_sbuffer_init(&sbuf); + msgpack_packer pk; + msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write); + + msgpack_pack_ext(&pk, size, 82); + msgpack_pack_ext_body(&pk, buf, size); + msgpack_zone z; + msgpack_zone_init(&z, 2048); + msgpack_object obj; + msgpack_unpack_return ret = + msgpack_unpack(sbuf.data, sbuf.size, NULL, &z, &obj); + EXPECT_EQ(MSGPACK_UNPACK_SUCCESS, ret); + EXPECT_EQ(MSGPACK_OBJECT_EXT, obj.type); + EXPECT_EQ(82, obj.via.ext.type); + ASSERT_EQ(size, obj.via.ext.size); + EXPECT_EQ(0, memcmp(buf, obj.via.ext.ptr, size)); + msgpack_zone_destroy(&z); + msgpack_sbuffer_destroy(&sbuf); + free(buf); +} +#endif // SIZE_MAX > UINT32_MAX + TEST(MSGPACKC, simple_buffer_timestamp_32) { msgpack_timestamp ts = {