aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2020-10-08 20:27:27 -0700
committerVasil Dimov <vd@FreeBSD.org>2020-10-09 10:32:19 +0200
commit1d3ec2a1fda7446323786a52da1fd109c01aa6fb (patch)
tree7d4dd26269bf40b771e360c64ca3a12388ec5880
parent6af9b31bfc6dd6086d245c00eb7cff762fc34a1e (diff)
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.
-rw-r--r--src/serialize.h22
1 files changed, 17 insertions, 5 deletions
diff --git a/src/serialize.h b/src/serialize.h
index 7a94e704b2..d9ca984f9c 100644
--- a/src/serialize.h
+++ b/src/serialize.h
@@ -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");
}