diff --git a/src/serialize.h b/src/serialize.h --- a/src/serialize.h +++ b/src/serialize.h @@ -23,7 +23,11 @@ #include #include -static const uint64_t MAX_SIZE = 0x02000000; +/** + * The maximum size of a serialized object in bytes or number of elements + * (for eg vectors) when the size is encoded as CompactSize. + */ +static constexpr uint64_t MAX_SIZE = 0x02000000; /** * Maximum amount of memory (in bytes) to allocate at once when deserializing @@ -445,7 +449,15 @@ return; } -template uint64_t ReadCompactSize(Stream &is) { +/** + * Decode a CompactSize-encoded variable-length integer. + * + * As these are primarily used to encode the size of vector-like serializations, + * by default a range check is performed. When used as a generic number + * encoding, range_check should be set to false. + */ +template +uint64_t ReadCompactSize(Stream &is, bool range_check = true) { uint8_t chSize = ser_readdata8(is); uint64_t nSizeRet = 0; if (chSize < 253) { @@ -466,7 +478,7 @@ throw std::ios_base::failure("non-canonical ReadCompactSize()"); } } - if (nSizeRet > MAX_SIZE) { + if (range_check && nSizeRet > MAX_SIZE) { throw std::ios_base::failure("ReadCompactSize(): size too large"); } return nSizeRet; @@ -612,7 +624,7 @@ #define VARINT_MODE(obj, mode) Using>(obj) #define VARINT(obj) Using>(obj) -#define COMPACTSIZE(obj) Using(obj) +#define COMPACTSIZE(obj) Using>(obj) #define LIMITED_STRING(obj, n) LimitedString(REF(obj)) /** @@ -679,9 +691,9 @@ using BigEndianFormatter = CustomUintFormatter; /** Formatter for integers in CompactSize format. */ -struct CompactSizeFormatter { +template struct CompactSizeFormatter { template void Unser(Stream &s, I &v) { - uint64_t n = ReadCompactSize(s); + uint64_t n = ReadCompactSize(s, RangeCheck); if (n < std::numeric_limits::min() || n > std::numeric_limits::max()) { throw std::ios_base::failure("CompactSize exceeds limit of type");