mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 03:47:29 -03:00
Support bypassing range check in ReadCompactSize
This is needed when we want to encode an arbitrary number as CompactSize like node service flags, which is a bitmask and could be bigger than the usual size of an object.
This commit is contained in:
parent
6af9b31bfc
commit
1d3ec2a1fd
1 changed files with 17 additions and 5 deletions
|
@ -24,7 +24,11 @@
|
|||
#include <prevector.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. */
|
||||
static const unsigned int MAX_VECTOR_ALLOCATE = 5000000;
|
||||
|
@ -304,8 +308,14 @@ void WriteCompactSize(Stream& os, uint64_t nSize)
|
|||
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>
|
||||
uint64_t ReadCompactSize(Stream& is)
|
||||
uint64_t ReadCompactSize(Stream& is, bool range_check = true)
|
||||
{
|
||||
uint8_t chSize = ser_readdata8(is);
|
||||
uint64_t nSizeRet = 0;
|
||||
|
@ -331,8 +341,9 @@ uint64_t ReadCompactSize(Stream& is)
|
|||
if (nSizeRet < 0x100000000ULL)
|
||||
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");
|
||||
}
|
||||
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(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)
|
||||
|
||||
/** Serialization wrapper class for integers in VarInt format. */
|
||||
|
@ -529,12 +540,13 @@ struct CustomUintFormatter
|
|||
template<int Bytes> using BigEndianFormatter = CustomUintFormatter<Bytes, true>;
|
||||
|
||||
/** Formatter for integers in CompactSize format. */
|
||||
template<bool RangeCheck>
|
||||
struct CompactSizeFormatter
|
||||
{
|
||||
template<typename Stream, typename I>
|
||||
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()) {
|
||||
throw std::ios_base::failure("CompactSize exceeds limit of type");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue