From 1c47ce020a019a3d4246e6394176779ecdf9d502 Mon Sep 17 00:00:00 2001 From: RAJATH MOHARE Date: Thu, 29 Oct 2026 21:17:24 +0530 Subject: [PATCH] check destination capacity in msgpack_vrefbuffer_migrate msgpack_vrefbuffer_migrate decided whether to grow to->array by comparing to->tail + nused against vbuf->end, the end of the source's iovec array. The two arrays are separate allocations, so the result depended on heap layout rather than on the room left in `to`. When to->array sat above the source's array the realloc was skipped and the memcpy wrote nused iovecs past to->end. Compare nused against the free slots in `to` instead. This is the C counterpart of the C++ fix in ee24845, written as a count so the check never forms a pointer past to->end. Fixes #1197. --- src/vrefbuffer.c | 2 +- test/buffer_c.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/vrefbuffer.c b/src/vrefbuffer.c index c7dc9d421..52523b0b3 100644 --- a/src/vrefbuffer.c +++ b/src/vrefbuffer.c @@ -198,7 +198,7 @@ int msgpack_vrefbuffer_migrate(msgpack_vrefbuffer* vbuf, msgpack_vrefbuffer* to) { const size_t nused = (size_t)(vbuf->tail - vbuf->array); - if(to->tail + nused < vbuf->end) { + if(nused > (size_t)(to->end - to->tail)) { msgpack_iovec* nvec; const size_t tosize = (size_t)(to->tail - to->array); const size_t reqsize = nused + tosize; diff --git a/test/buffer_c.cpp b/test/buffer_c.cpp index 5e63aebb8..0407dd2bf 100644 --- a/test/buffer_c.cpp +++ b/test/buffer_c.cpp @@ -161,3 +161,42 @@ TEST(buffer, vrefbuffer_c) free(buf); msgpack_vrefbuffer_free(vbuf); } + +TEST(buffer, vrefbuffer_c_migrate_grows_destination) +{ + static const char payload[64] = "payload"; + msgpack_vrefbuffer a, b; + msgpack_vrefbuffer *vbuf, *to; + const msgpack_iovec *iov; + size_t i; + + EXPECT_TRUE(msgpack_vrefbuffer_init(&a, 0, 0)); + EXPECT_TRUE(msgpack_vrefbuffer_init(&b, 0, 0)); + for (i = 0; i < 20; ++i) { + EXPECT_EQ(0, msgpack_vrefbuffer_append_ref(&a, payload, sizeof(payload))); + EXPECT_EQ(0, msgpack_vrefbuffer_append_ref(&b, payload, sizeof(payload))); + } + + /* Migrate into the buffer whose iovec array sits higher in memory. + * With that layout a check against vbuf->end instead of to->end never + * grows `to`, although it has no room for the 20 incoming iovecs. */ + vbuf = &a; + to = &b; + if ((uintptr_t)a.array > (uintptr_t)b.array) { + vbuf = &b; + to = &a; + } + + EXPECT_EQ(0, msgpack_vrefbuffer_migrate(vbuf, to)); + EXPECT_EQ(0U, msgpack_vrefbuffer_veclen(vbuf)); + EXPECT_EQ(40U, msgpack_vrefbuffer_veclen(to)); + EXPECT_TRUE(to->tail <= to->end); + iov = msgpack_vrefbuffer_vec(to); + for (i = 0; i < 40; ++i) { + EXPECT_EQ((const void*)payload, (const void*)iov[i].iov_base); + EXPECT_EQ(sizeof(payload), iov[i].iov_len); + } + + msgpack_vrefbuffer_destroy(&a); + msgpack_vrefbuffer_destroy(&b); +}