@ -24,7 +24,11 @@
# include <prevector.h>
# include <prevector.h>
# include <span.h>
# include <span.h>
static const unsigned int 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 vectors. */
/** Maximum amount of memory (in bytes) to allocate at once when deserializing vectors. */
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000 ;
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000 ;
@ -304,8 +308,14 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
return ;
return ;
}
}
/**
* 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 < typename Stream >
template < typename Stream >
uint64_t ReadCompactSize ( Stream & is )
uint64_t ReadCompactSize ( Stream & is , bool range_check = true )
{
{
uint8_t chSize = ser_readdata8 ( is ) ;
uint8_t chSize = ser_readdata8 ( is ) ;
uint64_t nSizeRet = 0 ;
uint64_t nSizeRet = 0 ;
@ -331,8 +341,9 @@ uint64_t ReadCompactSize(Stream& is)
if ( nSizeRet < 0x100000000ULL )
if ( nSizeRet < 0x100000000ULL )
throw std : : ios_base : : failure ( " non-canonical ReadCompactSize() " ) ;
throw std : : ios_base : : failure ( " non-canonical ReadCompactSize() " ) ;
}
}
if ( nSizeRet > ( uint64_t ) MAX_SIZE )
if ( range_check & & nSizeRet > MAX_SIZE ) {
throw std : : ios_base : : failure ( " ReadCompactSize(): size too large " ) ;
throw std : : ios_base : : failure ( " ReadCompactSize(): size too large " ) ;
}
return nSizeRet ;
return nSizeRet ;
}
}
@ -466,7 +477,7 @@ static inline Wrapper<Formatter, T&> Using(T&& t) { return Wrapper<Formatter, T&
# define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
# define VARINT_MODE(obj, mode) Using<VarIntFormatter<mode>>(obj)
# define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
# define VARINT(obj) Using<VarIntFormatter<VarIntMode::DEFAULT>>(obj)
# define COMPACTSIZE(obj) Using<CompactSizeFormatter >(obj)
# define COMPACTSIZE(obj) Using<CompactSizeFormatter <true> >(obj)
# define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
# define LIMITED_STRING(obj,n) Using<LimitedStringFormatter<n>>(obj)
/** Serialization wrapper class for integers in VarInt format. */
/** Serialization wrapper class for integers in VarInt format. */
@ -529,12 +540,13 @@ struct CustomUintFormatter
template < int Bytes > using BigEndianFormatter = CustomUintFormatter < Bytes , true > ;
template < int Bytes > using BigEndianFormatter = CustomUintFormatter < Bytes , true > ;
/** Formatter for integers in CompactSize format. */
/** Formatter for integers in CompactSize format. */
template < bool RangeCheck >
struct CompactSizeFormatter
struct CompactSizeFormatter
{
{
template < typename Stream , typename I >
template < typename Stream , typename I >
void Unser ( Stream & s , I & v )
void Unser ( Stream & s , I & v )
{
{
uint64_t n = ReadCompactSize < Stream > ( s );
uint64_t n = ReadCompactSize < Stream > ( s , RangeCheck );
if ( n < std : : numeric_limits < I > : : min ( ) | | n > std : : numeric_limits < I > : : max ( ) ) {
if ( n < std : : numeric_limits < I > : : min ( ) | | n > std : : numeric_limits < I > : : max ( ) ) {
throw std : : ios_base : : failure ( " CompactSize exceeds limit of type " ) ;
throw std : : ios_base : : failure ( " CompactSize exceeds limit of type " ) ;
}
}