From 94ed45427c55529932a56bdce47495dbff84a1e6 Mon Sep 17 00:00:00 2001 From: Anthony Towns Date: Thu, 7 May 2026 02:56:18 +1000 Subject: [PATCH] serialize: add LimitedVectorFormatter --- src/serialize.h | 30 ++++++++++++++++++++++++++++++ src/test/serialize_tests.cpp | 25 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/serialize.h b/src/serialize.h index 2681b098a4e..5d38a510076 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -494,6 +494,7 @@ static inline Wrapper Using(T&& t) { return Wrapper>(obj) #define COMPACTSIZE(obj) Using>(obj) #define LIMITED_STRING(obj,n) Using>(obj) +#define LIMITED_VECTOR(obj,n) Using>(obj) /** Serialization wrapper class for integers in VarInt format. */ template @@ -790,6 +791,35 @@ struct DefaultFormatter static void Unser(Stream& s, T& t) { Unserialize(s, t); } }; +/** + * Limited vector formatter. Throws an error if a vector is oversized. + */ + +template +struct LimitedVectorFormatter +{ + template + void Unser(Stream& s, V& v) + { + Formatter formatter; + v.clear(); + size_t size = ReadCompactSize(s); + if (size > Limit) { + throw std::ios_base::failure("Vector length limit exceeded"); + } + v.reserve(size); + for (size_t i = 0; i < size; ++i) { + v.emplace_back(); + formatter.Unser(s, v.back()); + } + } + + template + void Ser(Stream& s, const V& v) + { + VectorFormatter{}.Ser(s, v); + } +}; diff --git a/src/test/serialize_tests.cpp b/src/test/serialize_tests.cpp index dd2c8cddcfc..9c2f16f03e3 100644 --- a/src/test/serialize_tests.cpp +++ b/src/test/serialize_tests.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -251,6 +252,30 @@ BOOST_AUTO_TEST_CASE(string_view) BOOST_CHECK_EQUAL(sv, s); } +BOOST_AUTO_TEST_CASE(limited_vector) +{ + const std::vector v = {1,2,3,4,-5,-6,-7,-8,-9,-10,10000,20000,-30000}; + + auto check = [&]() { + DataStream ss; + ss << v; + try { + std::vector r; + ss >> LIMITED_VECTOR(r, N); + BOOST_CHECK_LE(r.size(), N); + BOOST_CHECK(std::ranges::equal(r, v)); + } catch (const std::ios_base::failure&) { + BOOST_CHECK_GT(v.size(), N); + } + }; + check.operator()<0>(); + check.operator()<10>(); + check.operator()<12>(); + check.operator()<13>(); + check.operator()<14>(); + check.operator()<100>(); +} + BOOST_AUTO_TEST_CASE(class_methods) { int intval(100);