24
24
#include < prevector.h>
25
25
#include < span.h>
26
26
27
- static const unsigned int MAX_SIZE = 0x02000000 ;
27
+ /* *
28
+ * The maximum size of a serialized object in bytes or number of elements
29
+ * (for eg vectors) when the size is encoded as CompactSize.
30
+ */
31
+ static constexpr uint64_t MAX_SIZE = 0x02000000 ;
28
32
29
33
/* * Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */
30
34
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000 ;
@@ -304,8 +308,14 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
304
308
return ;
305
309
}
306
310
311
+ /* *
312
+ * Decode a CompactSize-encoded variable-length integer.
313
+ *
314
+ * As these are primarily used to encode the size of vector-like serializations, by default a range
315
+ * check is performed. When used as a generic number encoding, range_check should be set to false.
316
+ */
307
317
template <typename Stream>
308
- uint64_t ReadCompactSize (Stream& is)
318
+ uint64_t ReadCompactSize (Stream& is, bool range_check = true )
309
319
{
310
320
uint8_t chSize = ser_readdata8 (is);
311
321
uint64_t nSizeRet = 0 ;
@@ -331,8 +341,9 @@ uint64_t ReadCompactSize(Stream& is)
331
341
if (nSizeRet < 0x100000000ULL )
332
342
throw std::ios_base::failure (" non-canonical ReadCompactSize()" );
333
343
}
334
- if (nSizeRet > ( uint64_t ) MAX_SIZE)
344
+ if (range_check && nSizeRet > MAX_SIZE) {
335
345
throw std::ios_base::failure (" ReadCompactSize(): size too large" );
346
+ }
336
347
return nSizeRet;
337
348
}
338
349
@@ -466,7 +477,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
466
477
467
478
#define VARINT_MODE (obj, mode ) Using<VarIntFormatter<mode>>(obj)
468
479
#define VARINT (obj ) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
469
- #define COMPACTSIZE (obj ) Using<CompactSizeFormatter>(obj)
480
+ #define COMPACTSIZE (obj ) Using<CompactSizeFormatter< true > >(obj)
470
481
#define LIMITED_STRING (obj,n ) Using<LimitedStringFormatter<n>>(obj)
471
482
472
483
/* * Serialization wrapper class for integers in VarInt format. */
@@ -529,12 +540,13 @@ struct CustomUintFormatter
529
540
template <int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true >;
530
541
531
542
/* * Formatter for integers in CompactSize format. */
543
+ template <bool RangeCheck>
532
544
struct CompactSizeFormatter
533
545
{
534
546
template <typename Stream, typename I>
535
547
void Unser (Stream& s, I& v)
536
548
{
537
- uint64_t n = ReadCompactSize<Stream>(s);
549
+ uint64_t n = ReadCompactSize<Stream>(s, RangeCheck );
538
550
if (n < std::numeric_limits<I>::min () || n > std::numeric_limits<I>::max ()) {
539
551
throw std::ios_base::failure (" CompactSize exceeds limit of type" );
540
552
}
0 commit comments