Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package msgpack-cxx for openSUSE:Factory checked in at 2026-08-27 18:52:09 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/msgpack-cxx (Old) and /work/SRC/openSUSE:Factory/.msgpack-cxx.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "msgpack-cxx" Thu Aug 27 18:52:09 2026 rev:8 rq:1373897 version:9.0.0 Changes: -------- --- /work/SRC/openSUSE:Factory/msgpack-cxx/msgpack-cxx.changes 2026-05-31 18:31:16.043431531 +0200 +++ /work/SRC/openSUSE:Factory/.msgpack-cxx.new.1265/msgpack-cxx.changes 2026-08-27 18:55:30.987252673 +0200 @@ -1,0 +2,14 @@ +Wed Aug 26 19:58:02 UTC 2026 - Jan Engelhardt <[email protected]> + +- Update to release 9.0.0 + * Fix out-of-bounds reads and writes, heap buffer overflows, + double frees, use-after-frees, nullptr dereferencing and + integer overflows. + * Breaking change: Fix ext32 max size truncation on 64-bit by + widening visit_ext size to size_t. + If you have a custom visitor that implements visit_ext(), + widen its size parameter from uint32_t to std::size_t: + Before: bool visit_ext(const char *v, uint32_t size) + After: bool visit_ext(const char *v, std::size_t size) + +------------------------------------------------------------------- Old: ---- msgpack-cxx-8.0.0.tar.gz New: ---- msgpack-cxx-9.0.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ msgpack-cxx.spec ++++++ --- /var/tmp/diff_new_pack.xYxjDp/_old 2026-08-27 18:55:31.664276309 +0200 +++ /var/tmp/diff_new_pack.xYxjDp/_new 2026-08-27 18:55:31.665276344 +0200 @@ -17,7 +17,7 @@ Name: msgpack-cxx -Version: 8.0.0 +Version: 9.0.0 Release: 0 Summary: Object serialization library for cross-language communication (C++ interface) License: BSL-1.0 ++++++ _scmsync.obsinfo ++++++ --- /var/tmp/diff_new_pack.xYxjDp/_old 2026-08-27 18:55:31.721278299 +0200 +++ /var/tmp/diff_new_pack.xYxjDp/_new 2026-08-27 18:55:31.724278404 +0200 @@ -1,5 +1,5 @@ -mtime: 1780241979 -commit: 7933327211a3ca1fe99b8f6afe791e1acaa946287734c9f268304472e63a65cd +mtime: 1787775230 +commit: 815d2a72cd42c686d2e46effa413858e67a92b858b9a9bd92ed4d4958504933d url: https://src.opensuse.org/clibs/msgpack-cxx revision: master ++++++ build.specials.obscpio ++++++ ++++++ build.specials.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.gitignore new/.gitignore --- old/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/.gitignore 2026-08-26 22:13:50.000000000 +0200 @@ -0,0 +1 @@ +.osc ++++++ msgpack-cxx-8.0.0.tar.gz -> msgpack-cxx-9.0.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/README.md new/msgpack-cxx-9.0.0/README.md --- old/msgpack-cxx-8.0.0/README.md 2026-05-30 12:31:43.000000000 +0200 +++ new/msgpack-cxx-9.0.0/README.md 2026-08-25 10:56:00.000000000 +0200 @@ -1,7 +1,7 @@ `msgpack` for C++ =================== -Version 8.0.0 [](https://github.com/msgpack/msgpack-c/actions) [](https://ci.appveyor.com/project/redboltz/msgpack-c/branch/cpp_master) +Version 9.0.0 [](https://github.com/msgpack/msgpack-c/actions) [](https://ci.appveyor.com/project/redboltz/msgpack-c/branch/cpp_master) [](https://app.codecov.io/gh/msgpack/msgpack-c/tree/cpp_master) It's like JSON but smaller and faster. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/erb/v1/cpp03_zone.hpp.erb new/msgpack-cxx-9.0.0/erb/v1/cpp03_zone.hpp.erb --- old/msgpack-cxx-8.0.0/erb/v1/cpp03_zone.hpp.erb 2023-11-23 05:04:23.000000000 +0100 +++ new/msgpack-cxx-9.0.0/erb/v1/cpp03_zone.hpp.erb 2026-08-25 10:56:00.000000000 +0200 @@ -249,6 +249,10 @@ sz = tmp_sz; } + if((sizeof(chunk) + sz) < sz) { + throw std::bad_alloc(); + } + chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz)); if (!c) throw std::bad_alloc(); @@ -283,8 +287,16 @@ { using std::swap; swap(m_chunk_size, o.m_chunk_size); - swap(m_chunk_list, o.m_chunk_list); - swap(m_finalizer_array, o.m_finalizer_array); + // Swap the internal pointers directly. std::swap on chunk_list / + // finalizer_array would construct a temporary and run its owning + // destructor (freeing chunks and executing finalizers) on memory that + // has just been transferred to the other zone -> double free / UAF. + swap(m_chunk_list.m_free, o.m_chunk_list.m_free); + swap(m_chunk_list.m_ptr, o.m_chunk_list.m_ptr); + swap(m_chunk_list.m_head, o.m_chunk_list.m_head); + swap(m_finalizer_array.m_tail, o.m_finalizer_array.m_tail); + swap(m_finalizer_array.m_end, o.m_finalizer_array.m_end); + swap(m_finalizer_array.m_array, o.m_finalizer_array.m_array); } template <typename T> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/array_ref.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/array_ref.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/array_ref.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/array_ref.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -78,10 +78,8 @@ template <typename U> bool operator==(array_ref<U> const& t) const { if (N != t.size()) return false; - T const* pself = data; - U const* pother = t.data; - for (; pself != &data[N]; ++pself, ++pother) { - if (*pself != *pother) return false; + for (std::size_t i = 0; i < N; ++i) { + if (!(data[i] == t.data[i])) return false; } return true; } @@ -92,28 +90,32 @@ template <typename U> bool operator< (array_ref<U> const& t) const { - T const* pself = data; - U const* pother = t.data; - for (; pself != &data[N] && pother != t.data[t.size()]; ++pself, ++pother) { - if (*pself < *pother) return true; + std::size_t n = (N < t.size()) ? N : t.size(); + for (std::size_t i = 0; i < n; ++i) { + if (data[i] < t.data[i]) return true; + if (t.data[i] < data[i]) return false; } - if (N < t.size()) return true; - return false; + return N < t.size(); } template <typename U> bool operator> (array_ref<U> const& t) const { - return t.data < data; + std::size_t n = (N < t.size()) ? N : t.size(); + for (std::size_t i = 0; i < n; ++i) { + if (t.data[i] < data[i]) return true; + if (data[i] < t.data[i]) return false; + } + return t.size() < N; } template <typename U> bool operator<= (array_ref<U> const& t) const { - return !(t.data < data); + return !(*this > t); } template <typename U> bool operator>= (array_ref<U> const& t) const { - return !(data < t.data); + return !(*this < t); } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/carray.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/carray.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/carray.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/carray.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -30,11 +30,9 @@ if (o.via.array.size > N) { throw msgpack::type_error(); } msgpack::object* p = o.via.array.ptr; msgpack::object* const pend = o.via.array.ptr + o.via.array.size; - do { + for (; p < pend; ++p, ++v) { p->convert(*v); - ++p; - ++v; - } while(p < pend); + } return o; } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/array_char.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/array_char.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/array_char.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/array_char.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -36,7 +36,7 @@ break; case msgpack::type::STR: if(o.via.str.size > N) { throw msgpack::type_error(); } - std::memcpy(v.data(), o.via.str.ptr, N); + std::memcpy(v.data(), o.via.str.ptr, o.via.str.size); break; default: throw msgpack::type_error(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/array_unsigned_char.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/array_unsigned_char.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/array_unsigned_char.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/array_unsigned_char.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -36,7 +36,7 @@ break; case msgpack::type::STR: if(o.via.str.size > N) { throw msgpack::type_error(); } - std::memcpy(v.data(), o.via.str.ptr, N); + std::memcpy(v.data(), o.via.str.ptr, o.via.str.size); break; default: throw msgpack::type_error(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/tuple.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/tuple.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/cpp11/tuple.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/cpp11/tuple.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -114,6 +114,7 @@ std::tuple<Args...> operator()( msgpack::object const& o) const { if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); } + if (o.via.array.size < sizeof...(Args)) { throw msgpack::type_error(); } return StdTupleAs<Args...>::as(o); } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/detail/cpp11_msgpack_tuple.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/detail/cpp11_msgpack_tuple.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/detail/cpp11_msgpack_tuple.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/detail/cpp11_msgpack_tuple.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -131,7 +131,8 @@ static void convert ( msgpack::object const& o, Tuple& v) { - o.via.array.ptr[0].convert<typename std::remove_reference<decltype(v.template get<0>())>::type>(v.template get<0>()); + if (o.via.array.size >= 1) + o.via.array.ptr[0].convert<typename std::remove_reference<decltype(v.template get<0>())>::type>(v.template get<0>()); } }; @@ -150,6 +151,7 @@ msgpack::type::tuple<Args...> operator()( msgpack::object const& o) const { if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); } + if (o.via.array.size < sizeof...(Args)) { throw msgpack::type_error(); } return MsgpackTupleAs<Args...>::as(o); } }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/ext.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/ext.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/adaptor/ext.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/adaptor/ext.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -149,7 +149,7 @@ } bool operator== (const ext_ref& x) const { - return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size) == 0; + return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size + 1) == 0; } bool operator!= (const ext_ref& x) const { @@ -159,13 +159,13 @@ bool operator< (const ext_ref& x) const { if (m_size < x.m_size) return true; if (m_size > x.m_size) return false; - return std::memcmp(m_ptr, x.m_ptr, m_size) < 0; + return std::memcmp(m_ptr, x.m_ptr, m_size + 1) < 0; } bool operator> (const ext_ref& x) const { if (m_size > x.m_size) return true; if (m_size < x.m_size) return false; - return std::memcmp(m_ptr, x.m_ptr, m_size) > 0; + return std::memcmp(m_ptr, x.m_ptr, m_size + 1) > 0; } private: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/detail/cpp03_zone.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/detail/cpp03_zone.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/detail/cpp03_zone.hpp 2024-11-02 02:56:19.000000000 +0100 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/detail/cpp03_zone.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -294,6 +294,10 @@ sz = tmp_sz; } + if((sizeof(chunk) + sz) < sz) { + throw std::bad_alloc(); + } + chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz)); if (!c) throw std::bad_alloc(); @@ -328,8 +332,16 @@ { using std::swap; swap(m_chunk_size, o.m_chunk_size); - swap(m_chunk_list, o.m_chunk_list); - swap(m_finalizer_array, o.m_finalizer_array); + // Swap the internal pointers directly. std::swap on chunk_list / + // finalizer_array would construct a temporary and run its owning + // destructor (freeing chunks and executing finalizers) on memory that + // has just been transferred to the other zone -> double free / UAF. + swap(m_chunk_list.m_free, o.m_chunk_list.m_free); + swap(m_chunk_list.m_ptr, o.m_chunk_list.m_ptr); + swap(m_chunk_list.m_head, o.m_chunk_list.m_head); + swap(m_finalizer_array.m_tail, o.m_finalizer_array.m_tail); + swap(m_finalizer_array.m_end, o.m_finalizer_array.m_end); + swap(m_finalizer_array.m_array, o.m_finalizer_array.m_array); } template <typename T> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/detail/cpp11_zone.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/detail/cpp11_zone.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/detail/cpp11_zone.hpp 2023-11-23 05:04:23.000000000 +0100 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/detail/cpp11_zone.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -150,6 +150,8 @@ chunk_list(chunk_list&& other) noexcept :m_free(other.m_free), m_ptr(other.m_ptr), m_head(other.m_head) { + other.m_free = 0; + other.m_ptr = MSGPACK_NULLPTR; other.m_head = MSGPACK_NULLPTR; } chunk_list& operator=(chunk_list&& other) noexcept @@ -208,7 +210,18 @@ T* allocate(Args... args); zone(zone&&) = default; - zone& operator=(zone&&) = default; + zone& operator=(zone&& other) { + if (this != &other) { + // Destroy in the correct order: run finalizers first (while our + // chunks are still alive), then release our chunks. A defaulted + // move-assignment would free the chunks before the finalizers run, + // causing use-after-free of zone-allocated objects. + m_finalizer_array = std::move(other.m_finalizer_array); + m_chunk_list = std::move(other.m_chunk_list); + m_chunk_size = other.m_chunk_size; + } + return *this; + } zone(const zone&) = delete; zone& operator=(const zone&) = delete; @@ -281,6 +294,10 @@ sz = tmp_sz; } + if((sizeof(chunk) + sz) < sz) { + throw std::bad_alloc(); + } + chunk* c = static_cast<chunk*>(::malloc(sizeof(chunk) + sz)); if (!c) throw std::bad_alloc(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/object.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/object.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/object.hpp 2026-05-29 12:20:58.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/object.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -265,7 +265,7 @@ break; case msgpack::type::EXT: msgpack::detail::check_container_size<sizeof(std::size_t)>(m_current->via.ext.size); - if (!v.visit_ext(m_current->via.ext.ptr, m_current->via.ext.size + 1)) return; + if (!v.visit_ext(m_current->via.ext.ptr, static_cast<std::size_t>(m_current->via.ext.size) + 1)) return; break; case msgpack::type::ARRAY: if (!v.start_array(m_current->via.array.size)) return; @@ -351,9 +351,9 @@ m_packer.pack_bin_body(v, size); return true; } - bool visit_ext(const char* v, uint32_t size) { + bool visit_ext(const char* v, std::size_t size) { m_packer.pack_ext(size - 1, static_cast<int8_t>(*v)); - m_packer.pack_ext_body(v + 1, size - 1); + m_packer.pack_ext_body(v + 1, static_cast<uint32_t>(size - 1)); return true; } bool start_array(uint32_t num_elements) { @@ -470,7 +470,7 @@ m_os << "\"BIN(size:" << size << ")\""; return true; } - bool visit_ext(const char* v, uint32_t size) { + bool visit_ext(const char* v, std::size_t size) { if (size == 0) { m_os << "\"EXT(size:0)\""; } @@ -560,7 +560,7 @@ m_size += msgpack::aligned_size(size, MSGPACK_ZONE_ALIGNOF(char)); return true; } - bool visit_ext(const char*, uint32_t size) { + bool visit_ext(const char*, std::size_t size) { m_size += msgpack::aligned_size(size, MSGPACK_ZONE_ALIGNOF(char)); return true; } @@ -741,12 +741,12 @@ std::memcpy(ptr, v, size); return true; } - bool visit_ext(const char* v, uint32_t size) { + bool visit_ext(const char* v, std::size_t size) { m_ptr->type = msgpack::type::EXT; // v contains type but length(size) doesn't count the type byte. // See https://github.com/msgpack/msgpack/blob/master/spec.md#ext-format-family - m_ptr->via.ext.size = size - 1; + m_ptr->via.ext.size = static_cast<uint32_t>(size - 1); char* ptr = static_cast<char*>(m_zone.allocate_align(size, MSGPACK_ZONE_ALIGNOF(char))); m_ptr->via.ext.ptr = ptr; @@ -941,7 +941,7 @@ } return true; } - bool visit_ext(const char* v, uint32_t size) { + bool visit_ext(const char* v, std::size_t size) { if (m_ptr->type != msgpack::type::EXT || m_ptr->via.ext.size != size - 1 || std::memcmp(m_ptr->via.ext.ptr, v, size) != 0) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/unpack.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/unpack.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/unpack.hpp 2023-08-29 16:27:11.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/unpack.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -21,6 +21,7 @@ #include "msgpack/assert.hpp" #include <memory> +#include <limits> #if !defined(MSGPACK_USE_CPP03) @@ -166,12 +167,12 @@ inline void unpack_str(unpack_user& u, const char* p, uint32_t l, msgpack::object& o) { o.type = msgpack::type::STR; + if (l > u.limit().str()) throw msgpack::str_size_overflow("str size overflow"); if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { o.via.str.ptr = p; u.set_referenced(true); } else if (l > 0) { - if (l > u.limit().str()) throw msgpack::str_size_overflow("str size overflow"); char* tmp = static_cast<char*>(u.zone().allocate_align(l, MSGPACK_ZONE_ALIGNOF(char))); std::memcpy(tmp, p, l); o.via.str.ptr = tmp; @@ -185,12 +186,12 @@ inline void unpack_bin(unpack_user& u, const char* p, uint32_t l, msgpack::object& o) { o.type = msgpack::type::BIN; + if (l > u.limit().bin()) throw msgpack::bin_size_overflow("bin size overflow"); if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { o.via.bin.ptr = p; u.set_referenced(true); } else if (l > 0) { - if (l > u.limit().bin()) throw msgpack::bin_size_overflow("bin size overflow"); char* tmp = static_cast<char*>(u.zone().allocate_align(l, MSGPACK_ZONE_ALIGNOF(char))); std::memcpy(tmp, p, l); o.via.bin.ptr = tmp; @@ -204,12 +205,12 @@ inline void unpack_ext(unpack_user& u, const char* p, std::size_t l, msgpack::object& o) { o.type = msgpack::type::EXT; + if (l > u.limit().ext()) throw msgpack::ext_size_overflow("ext size overflow"); if (u.reference_func() && u.reference_func()(o.type, l, u.user_data())) { o.via.ext.ptr = p; u.set_referenced(true); } else { - if (l > u.limit().ext()) throw msgpack::ext_size_overflow("ext size overflow"); char* tmp = static_cast<char*>(u.zone().allocate_align(l, MSGPACK_ZONE_ALIGNOF(char))); std::memcpy(tmp, p, l); o.via.ext.ptr = tmp; @@ -1104,8 +1105,10 @@ } inline unpacker& unpacker::operator=(unpacker&& other) { - this->~unpacker(); - new (this) unpacker(std::move(other)); + if (this != &other) { + this->~unpacker(); + new (this) unpacker(std::move(other)); + } return *this; } @@ -1138,6 +1141,9 @@ } if(m_off == COUNTER_SIZE) { + if(size > std::numeric_limits<std::size_t>::max() - m_used) { + throw std::bad_alloc(); + } std::size_t next_size = (m_used + m_free) * 2; // include COUNTER_SIZE while(next_size < size + m_used) { std::size_t tmp_next_size = next_size * 2; @@ -1159,6 +1165,9 @@ } else { std::size_t next_size = m_initial_buffer_size; // include COUNTER_SIZE std::size_t not_parsed = m_used - m_off; + if(size > std::numeric_limits<std::size_t>::max() - not_parsed - COUNTER_SIZE) { + throw std::bad_alloc(); + } while(next_size < size + not_parsed + COUNTER_SIZE) { std::size_t tmp_next_size = next_size * 2; if (tmp_next_size <= next_size) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v1/vrefbuffer.hpp new/msgpack-cxx-9.0.0/include/msgpack/v1/vrefbuffer.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v1/vrefbuffer.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v1/vrefbuffer.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -213,7 +213,7 @@ empty->next = MSGPACK_NULLPTR; const size_t nused = static_cast<size_t>(m_tail - m_array); - if(to->m_tail + nused < m_end) { + if(to->m_tail + nused > to->m_end) { const size_t tosize = static_cast<size_t>(to->m_tail - to->m_array); const size_t reqsize = nused + tosize; size_t nnext = static_cast<size_t>(to->m_end - to->m_array) * 2; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v2/create_object_visitor.hpp new/msgpack-cxx-9.0.0/include/msgpack/v2/create_object_visitor.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v2/create_object_visitor.hpp 2023-08-29 16:27:11.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v2/create_object_visitor.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -44,8 +44,10 @@ m_stack[0] = &m_obj; } create_object_visitor& operator=(create_object_visitor&& other) { - this->~create_object_visitor(); - new (this) create_object_visitor(std::move(other)); + if (this != &other) { + this->~create_object_visitor(); + new (this) create_object_visitor(std::move(other)); + } return *this; } #endif // !defined(MSGPACK_USE_CPP03) @@ -154,7 +156,7 @@ } return true; } - bool visit_ext(const char* v, uint32_t size) { + bool visit_ext(const char* v, std::size_t size) { MSGPACK_ASSERT(v || size == 0); if (size > m_limit.ext()) throw msgpack::ext_size_overflow("ext size overflow"); msgpack::object* obj = m_stack.back(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v2/null_visitor.hpp new/msgpack-cxx-9.0.0/include/msgpack/v2/null_visitor.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v2/null_visitor.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v2/null_visitor.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -43,7 +43,7 @@ bool visit_bin(const char* /*v*/, uint32_t /*size*/) { return true; } - bool visit_ext(const char* /*v*/, uint32_t /*size*/) { + bool visit_ext(const char* /*v*/, std::size_t /*size*/) { return true; } bool start_array(uint32_t /*num_elements*/) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v2/parse.hpp new/msgpack-cxx-9.0.0/include/msgpack/v2/parse.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v2/parse.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v2/parse.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -13,6 +13,8 @@ #if MSGPACK_DEFAULT_API_VERSION >= 2 #include <cstddef> +#include <limits> +#include <new> #include "msgpack/unpack_define.hpp" #include "msgpack/parse_return.hpp" @@ -479,7 +481,7 @@ load<uint8_t>(tmp, n); m_trail = tmp + 1; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -521,7 +523,7 @@ load<uint16_t>(tmp, n); m_trail = tmp + 1; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -565,7 +567,7 @@ m_trail = tmp; ++m_trail; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -585,7 +587,7 @@ if (upr != PARSE_CONTINUE) return upr; } break; case MSGPACK_ACS_EXT_VALUE: { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } break; @@ -761,6 +763,14 @@ void expand_buffer(std::size_t size); parse_return execute_imp(); +protected: + // Re-point the buffer-hook, e.g. after a move of the owning object so that + // the hook refers to the moved-to object's member rather than the + // moved-from (soon to be destroyed) object's member. + void set_referenced_buffer_hook(ReferencedBufferHook& hook) { + m_referenced_buffer_hook = &hook; + } + private: char* m_buffer; std::size_t m_used; @@ -768,7 +778,7 @@ std::size_t m_off; std::size_t m_parsed; std::size_t m_initial_buffer_size; - ReferencedBufferHook& m_referenced_buffer_hook; + ReferencedBufferHook* m_referenced_buffer_hook; #if defined(MSGPACK_USE_CPP03) private: @@ -785,7 +795,7 @@ inline parser<VisitorHolder, ReferencedBufferHook>::parser( ReferencedBufferHook& hook, std::size_t initial_buffer_size) - :m_referenced_buffer_hook(hook) + :m_referenced_buffer_hook(&hook) { if(initial_buffer_size < COUNTER_SIZE) { initial_buffer_size = COUNTER_SIZE; @@ -828,8 +838,10 @@ template <typename VisitorHolder, typename ReferencedBufferHook> inline parser<VisitorHolder, ReferencedBufferHook>& parser<VisitorHolder, ReferencedBufferHook>::operator=(this_type&& other) { - this->~parser(); - new (this) this_type(std::move(other)); + if (this != &other) { + this->~parser(); + new (this) this_type(std::move(other)); + } return *this; } @@ -865,6 +877,9 @@ } if(m_off == COUNTER_SIZE) { + if(size > std::numeric_limits<std::size_t>::max() - m_used) { + throw std::bad_alloc(); + } std::size_t next_size = (m_used + m_free) * 2; // include COUNTER_SIZE while(next_size < size + m_used) { std::size_t tmp_next_size = next_size * 2; @@ -886,6 +901,9 @@ } else { std::size_t next_size = m_initial_buffer_size; // include COUNTER_SIZE std::size_t not_parsed = m_used - m_off; + if(size > std::numeric_limits<std::size_t>::max() - not_parsed - COUNTER_SIZE) { + throw std::bad_alloc(); + } while(next_size < size + not_parsed + COUNTER_SIZE) { std::size_t tmp_next_size = next_size * 2; if (tmp_next_size <= next_size) { @@ -906,7 +924,7 @@ if(static_cast<VisitorHolder&>(*this).referenced()) { try { - m_referenced_buffer_hook(m_buffer); + (*m_referenced_buffer_hook)(m_buffer); } catch (...) { ::free(tmp); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v2/unpack.hpp new/msgpack-cxx-9.0.0/include/msgpack/v2/unpack.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v2/unpack.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v2/unpack.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -48,6 +48,27 @@ set_referenced(false); } +#if !defined(MSGPACK_USE_CPP03) + unpacker(unpacker&& other) + :parser_t(std::move(other)), + detail::create_object_visitor(std::move(other)), + m_z(std::move(other.m_z)), + m_finalizer(std::move(other.m_finalizer)) { + // The parser base copied a hook pointer that still refers to the + // moved-from object's m_finalizer; re-point it to our own. The zone + // itself is heap-allocated and only ownership moved, so the zone + // pointers held by the visitor and by m_finalizer stay valid. + parser_t::set_referenced_buffer_hook(m_finalizer); + } + unpacker& operator=(unpacker&& other) { + if (this != &other) { + this->~unpacker(); + new (this) unpacker(std::move(other)); + } + return *this; + } +#endif // !defined(MSGPACK_USE_CPP03) + detail::create_object_visitor& visitor() { return *this; } /// Unpack one msgpack::object. /** diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v2/x3_parse.hpp new/msgpack-cxx-9.0.0/include/msgpack/v2/x3_parse.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v2/x3_parse.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v2/x3_parse.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -214,7 +214,7 @@ ( [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); - app_specific.vis.visit_negative_integer(_attr(ctx)); + app_specific.vis.visit_positive_integer(_attr(ctx)); } ) ] @@ -592,7 +592,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -616,7 +616,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -640,7 +640,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -664,7 +664,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -688,7 +688,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -712,7 +712,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -736,7 +736,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) @@ -760,7 +760,7 @@ [](auto& ctx){ auto& app_specific = x3::get<tag_app_specific>(ctx).get(); auto const& ext = _attr(ctx); - auto size = static_cast<uint32_t>(std::distance(ext.begin(), ext.end())); + auto size = static_cast<std::size_t>(std::distance(ext.begin(), ext.end())); app_specific.vis.visit_ext(size ? &ext.front() : nullptr, size); } ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/v3/parse.hpp new/msgpack-cxx-9.0.0/include/msgpack/v3/parse.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/v3/parse.hpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/v3/parse.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -488,7 +488,7 @@ load<uint8_t>(tmp, n); m_trail = tmp + 1; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -530,7 +530,7 @@ load<uint16_t>(tmp, n); m_trail = tmp + 1; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -574,7 +574,7 @@ m_trail = tmp; ++m_trail; if(m_trail == 0) { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } @@ -594,7 +594,7 @@ if (upr != PARSE_CONTINUE) return upr; } break; case MSGPACK_ACS_EXT_VALUE: { - bool visret = holder().visitor().visit_ext(n, static_cast<uint32_t>(m_trail)); + bool visret = holder().visitor().visit_ext(n, m_trail); parse_return upr = after_visit_proc(visret, off); if (upr != PARSE_CONTINUE) return upr; } break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/include/msgpack/version_master.hpp new/msgpack-cxx-9.0.0/include/msgpack/version_master.hpp --- old/msgpack-cxx-8.0.0/include/msgpack/version_master.hpp 2026-05-30 12:31:43.000000000 +0200 +++ new/msgpack-cxx-9.0.0/include/msgpack/version_master.hpp 2026-08-25 10:56:00.000000000 +0200 @@ -1,3 +1,3 @@ -#define MSGPACK_VERSION_MAJOR 8 +#define MSGPACK_VERSION_MAJOR 9 #define MSGPACK_VERSION_MINOR 0 #define MSGPACK_VERSION_REVISION 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/test/CMakeLists.txt new/msgpack-cxx-9.0.0/test/CMakeLists.txt --- old/msgpack-cxx-8.0.0/test/CMakeLists.txt 2024-08-09 04:56:55.000000000 +0200 +++ new/msgpack-cxx-9.0.0/test/CMakeLists.txt 2026-08-25 10:56:00.000000000 +0200 @@ -47,6 +47,7 @@ msgpack_cpp11.cpp reference_cpp11.cpp reference_wrapper_cpp11.cpp + security_fixes_cpp11.cpp shared_ptr_cpp11.cpp unique_ptr_cpp11.cpp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/test/security_fixes_cpp11.cpp new/msgpack-cxx-9.0.0/test/security_fixes_cpp11.cpp --- old/msgpack-cxx-8.0.0/test/security_fixes_cpp11.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/msgpack-cxx-9.0.0/test/security_fixes_cpp11.cpp 2026-08-25 10:56:00.000000000 +0200 @@ -0,0 +1,175 @@ +#include <msgpack.hpp> + +#define BOOST_TEST_MODULE security_fixes +#include <boost/test/unit_test.hpp> + +#include <array> +#include <chrono> +#include <cstring> +#include <limits> +#include <string> +#include <tuple> +#include <vector> + +// Regression tests for memory-safety / correctness fixes. +// See the audit that accompanied the msgpack_unpacker_expand_buffer overflow fix. + +// A1: convert of an empty msgpack array into a C array must not dereference a +// null/oversized pointer. size < N leaves the remaining elements untouched; +// size > N throws. +BOOST_AUTO_TEST_CASE(carray_empty_array_no_crash) +{ + msgpack::object_handle oh = msgpack::unpack("\x90", 1); // empty fixarray + int v[3] = {7, 8, 9}; + oh.get().convert(v); // must not crash + BOOST_CHECK_EQUAL(v[0], 7); + + msgpack::object_handle oh2 = msgpack::unpack("\x94\x01\x02\x03\x04", 5); // 4 elems + int v2[3]; + BOOST_CHECK_THROW(oh2.get().convert(v2), msgpack::type_error); +} + +// A2: convert of an empty array into msgpack::type::tuple must not dereference +// a null pointer (the N==1 base specialization was missing the size guard). +BOOST_AUTO_TEST_CASE(msgpack_tuple_convert_empty_array) +{ + msgpack::object_handle oh = msgpack::unpack("\x90", 1); + msgpack::type::tuple<int> t; + oh.get().convert(t); // must not crash + BOOST_CHECK(true); +} + +// A3: as<tuple> on an array shorter than the tuple must throw, not read OOB +// (index computation size - sizeof...(Args) - 1 used to underflow). +BOOST_AUTO_TEST_CASE(tuple_as_short_array_throws) +{ + using tp = std::chrono::system_clock::time_point; + const char b[] = "\x91\x01"; // [1] + msgpack::object_handle oh = msgpack::unpack(b, 2); + BOOST_CHECK_THROW((oh.get().as<std::tuple<tp, tp, tp> >()), msgpack::type_error); + BOOST_CHECK_THROW((oh.get().as<msgpack::type::tuple<tp, tp, tp> >()), msgpack::type_error); +} + +// A4: converting a short STR into std::array<char, N> must copy only str.size +// bytes, not N (which over-read the source). +BOOST_AUTO_TEST_CASE(array_char_str_no_overread) +{ + msgpack::sbuffer sb; + msgpack::pack(sb, std::string("ab")); + msgpack::object_handle oh = msgpack::unpack(sb.data(), sb.size()); + std::array<char, 8> a; + a.fill('Z'); + oh.get().convert(a); + BOOST_CHECK_EQUAL(a[0], 'a'); + BOOST_CHECK_EQUAL(a[1], 'b'); + BOOST_CHECK_EQUAL(a[2], 'Z'); // untouched +} + +// B1: moving a (v2) unpacker must not leave the parser referencing the +// moved-from object's buffer hook. +BOOST_AUTO_TEST_CASE(unpacker_move_buffer_hook) +{ + msgpack::unpacker u1(MSGPACK_NULLPTR, MSGPACK_NULLPTR, 64); + msgpack::unpacker u2(std::move(u1)); + const char m[] = "\x92\xa3" "abc"; // array(2) + referencing str, 2nd elem missing + u2.reserve_buffer(5); + std::memcpy(u2.buffer(), m, 5); + u2.buffer_consumed(5); + msgpack::object_handle oh; + u2.next(oh); + u2.reserve_buffer(1 << 20); // exercises the referenced-buffer hook + BOOST_CHECK(true); + + // move-assignment and self-move-assignment + msgpack::unpacker u3(MSGPACK_NULLPTR, MSGPACK_NULLPTR, 64); + u3 = std::move(u2); +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wself-move" +#endif + u3 = std::move(u3); // self-move must not crash +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + BOOST_CHECK(true); +} + +// B2: zone move-assignment must run finalizers before freeing chunks. +BOOST_AUTO_TEST_CASE(zone_move_assignment) +{ + msgpack::zone z1; + z1.allocate<std::string>("a fairly long string that lives in the chunk"); + msgpack::zone z2; + z1 = std::move(z2); // must not use-after-free + BOOST_CHECK(true); +} + +// B4: vrefbuffer::migrate must grow the destination iovec array when needed. +BOOST_AUTO_TEST_CASE(vrefbuffer_migrate) +{ + // Use distinct 256-byte buffers so each write becomes its own iovec and + // fills the initial iovec array of both buffers, forcing migrate() to grow + // the destination array. + std::vector<std::string> bufs; + for (std::size_t i = 0; i < 8; ++i) bufs.push_back(std::string(256, static_cast<char>('a' + i))); + msgpack::vrefbuffer from; + msgpack::vrefbuffer to; + for (std::size_t i = 0; i < 4; ++i) from.write(bufs[i].data(), bufs[i].size()); + for (std::size_t i = 4; i < 8; ++i) to.write(bufs[i].data(), bufs[i].size()); + const size_t from_n = from.vector_size(); + const size_t to_n = to.vector_size(); + from.migrate(&to); // must not overflow to's iovec array + BOOST_CHECK_EQUAL(to.vector_size(), from_n + to_n); +} + +// B5: an impossibly large zone allocation must throw, not wrap the malloc size. +BOOST_AUTO_TEST_CASE(zone_allocate_overflow) +{ + msgpack::zone z; + BOOST_CHECK_THROW( + z.allocate_no_align(std::numeric_limits<std::size_t>::max() - 4), + std::bad_alloc); +} + +// C1: ext_ref comparison must include the whole payload (used to drop the last +// byte via memcmp(..., m_size)). +BOOST_AUTO_TEST_CASE(ext_ref_full_payload_compare) +{ + char ba[] = {7, 'x', 'y', 'A'}; + char bb[] = {7, 'x', 'y', 'B'}; + msgpack::type::ext_ref ra(ba, sizeof(ba)); + msgpack::type::ext_ref rb(bb, sizeof(bb)); + BOOST_CHECK(!(ra == rb)); + BOOST_CHECK(ra != rb); + BOOST_CHECK((ra < rb) || (rb < ra)); +} + +// C2: array_ref<T[N]> relational operators must compare element-wise. +BOOST_AUTO_TEST_CASE(array_ref_carray_compare) +{ + int x[3] = {1, 2, 3}; + int y[3] = {1, 2, 4}; + msgpack::type::array_ref<int[3]> rx = msgpack::type::make_array_ref(x); + msgpack::type::array_ref<int[3]> ry = msgpack::type::make_array_ref(y); + BOOST_CHECK(rx == rx); + BOOST_CHECK(rx != ry); + BOOST_CHECK(rx < ry); + BOOST_CHECK(ry > rx); + BOOST_CHECK(rx <= rx); + BOOST_CHECK(ry >= rx); +} + +// C3: v1 unpacker must enforce the str limit even on the reference path. +BOOST_AUTO_TEST_CASE(v1_unpacker_reference_path_limit) +{ + msgpack::sbuffer sb; + msgpack::pack(sb, std::string("0123456789")); + // array, map, str=2, ... + msgpack::v1::unpacker u(MSGPACK_NULLPTR, MSGPACK_NULLPTR, 64, + msgpack::unpack_limit(0xffffffff, 0xffffffff, 2)); + u.reserve_buffer(sb.size()); + std::memcpy(u.buffer(), sb.data(), sb.size()); + u.buffer_consumed(sb.size()); + msgpack::object_handle oh; + BOOST_CHECK_THROW(u.next(oh), msgpack::str_size_overflow); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/msgpack-cxx-8.0.0/test/streaming.cpp new/msgpack-cxx-9.0.0/test/streaming.cpp --- old/msgpack-cxx-8.0.0/test/streaming.cpp 2023-07-08 05:21:22.000000000 +0200 +++ new/msgpack-cxx-9.0.0/test/streaming.cpp 2026-08-25 10:56:00.000000000 +0200 @@ -333,3 +333,65 @@ } #endif // !defined(MSGPACK_USE_CPP03) + +// https://github.com/msgpack/msgpack-c/issues/1181 +template <typename Unpacker> +void reserve_buffer_overflow_rewound_impl() +{ + Unpacker pac(MSGPACK_NULLPTR, MSGPACK_NULLPTR, 8); + + // off == COUNTER_SIZE path: size + used would wrap + std::size_t request = std::numeric_limits<std::size_t>::max() - 2; + BOOST_CHECK_THROW(pac.reserve_buffer(request), std::bad_alloc); + + // a sane request still works + pac.reserve_buffer(64); + BOOST_CHECK_GE(pac.buffer_capacity(), static_cast<std::size_t>(64)); +} + +template <typename Unpacker> +void reserve_buffer_overflow_not_rewound_impl() +{ + Unpacker pac(MSGPACK_NULLPTR, MSGPACK_NULLPTR, 8); + + // consume part of the buffer so off != COUNTER_SIZE + msgpack::sbuffer sbuf; + msgpack::packer<msgpack::sbuffer> pk(&sbuf); + pk.pack(1); + pk.pack(2); + + pac.reserve_buffer(sbuf.size()); + std::memcpy(pac.buffer(), sbuf.data(), sbuf.size()); + pac.buffer_consumed(sbuf.size()); + + msgpack::object_handle oh; + BOOST_CHECK(pac.next(oh)); + BOOST_CHECK_EQUAL(oh.get().as<int>(), 1); + + std::size_t request = std::numeric_limits<std::size_t>::max() - 2; + BOOST_CHECK_THROW(pac.reserve_buffer(request), std::bad_alloc); + + // remaining data must still be parsable + BOOST_CHECK(pac.next(oh)); + BOOST_CHECK_EQUAL(oh.get().as<int>(), 2); +} + +BOOST_AUTO_TEST_CASE(reserve_buffer_overflow_rewound) +{ + reserve_buffer_overflow_rewound_impl<msgpack::unpacker>(); +} + +BOOST_AUTO_TEST_CASE(reserve_buffer_overflow_rewound_v1) +{ + reserve_buffer_overflow_rewound_impl<msgpack::v1::unpacker>(); +} + +BOOST_AUTO_TEST_CASE(reserve_buffer_overflow_not_rewound) +{ + reserve_buffer_overflow_not_rewound_impl<msgpack::unpacker>(); +} + +BOOST_AUTO_TEST_CASE(reserve_buffer_overflow_not_rewound_v1) +{ + reserve_buffer_overflow_not_rewound_impl<msgpack::v1::unpacker>(); +}
