Browse Source

Use size_t for RLP and decode length more carefully.

cl-refactor
chriseth 10 years ago
parent
commit
5a94ff0f97
  1. 75
      libdevcore/RLP.cpp
  2. 61
      libdevcore/RLP.h
  3. 2
      libethereum/Transaction.cpp

75
libdevcore/RLP.cpp

@ -49,12 +49,12 @@ RLP::iterator& RLP::iterator::operator++()
{ {
if (m_remaining) if (m_remaining)
{ {
m_lastItem.retarget(m_lastItem.next().data(), m_remaining); m_currentItem.retarget(m_currentItem.next().data(), m_remaining);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize()); m_currentItem = m_currentItem.cropped(0, RLP(m_currentItem, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining -= std::min<unsigned>(m_remaining, m_lastItem.size()); m_remaining -= std::min<size_t>(m_remaining, m_currentItem.size());
} }
else else
m_lastItem.retarget(m_lastItem.next().data(), 0); m_currentItem.retarget(m_currentItem.next().data(), 0);
return *this; return *this;
} }
@ -63,17 +63,17 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
if (_begin && _parent.isList()) if (_begin && _parent.isList())
{ {
auto pl = _parent.payload(); auto pl = _parent.payload();
m_lastItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize()); m_currentItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining = pl.size() - m_lastItem.size(); m_remaining = pl.size() - m_currentItem.size();
} }
else else
{ {
m_lastItem = _parent.data().cropped(_parent.data().size()); m_currentItem = _parent.data().cropped(_parent.data().size());
m_remaining = 0; m_remaining = 0;
} }
} }
RLP RLP::operator[](unsigned _i) const RLP RLP::operator[](size_t _i) const
{ {
if (_i < m_lastIndex) if (_i < m_lastIndex)
{ {
@ -100,7 +100,7 @@ RLPs RLP::toList() const
return ret; return ret;
} }
unsigned RLP::actualSize() const size_t RLP::actualSize() const
{ {
if (isNull()) if (isNull())
return 0; return 0;
@ -142,7 +142,7 @@ bool RLP::isInt() const
} }
else if (n < c_rlpListStart) else if (n < c_rlpListStart)
{ {
if ((int)m_data.size() <= 1 + n - c_rlpDataIndLenZero) if (m_data.size() <= size_t(1 + n - c_rlpDataIndLenZero))
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
return m_data[1 + n - c_rlpDataIndLenZero] != 0; return m_data[1 + n - c_rlpDataIndLenZero] != 0;
} }
@ -151,48 +151,58 @@ bool RLP::isInt() const
return false; return false;
} }
unsigned RLP::length() const size_t RLP::length() const
{ {
if (isNull()) if (isNull())
return 0; return 0;
requireGood(); requireGood();
unsigned ret = 0; size_t ret = 0;
byte n = m_data[0]; byte const n = m_data[0];
if (n < c_rlpDataImmLenStart) if (n < c_rlpDataImmLenStart)
return 1; return 1;
else if (n <= c_rlpDataIndLenZero) else if (n <= c_rlpDataIndLenZero)
return n - c_rlpDataImmLenStart; return n - c_rlpDataImmLenStart;
else if (n < c_rlpListStart) else if (n < c_rlpListStart)
{ {
if ((int)m_data.size() <= n - c_rlpDataIndLenZero) if (m_data.size() <= n - c_rlpDataIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1) if (m_data.size() > 1)
if (m_data[1] == 0) if (m_data[1] == 0)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
for (int i = 0; i < n - c_rlpDataIndLenZero; ++i) if (n - c_rlpDataIndLenZero > sizeof(ret))
// We did not check, but would most probably not fit in our memory.
BOOST_THROW_EXCEPTION(UndersizeRLP());
for (unsigned i = 0; i < n - c_rlpDataIndLenZero; ++i)
ret = (ret << 8) | m_data[i + 1]; ret = (ret << 8) | m_data[i + 1];
} }
else if (n <= c_rlpListIndLenZero) else if (n <= c_rlpListIndLenZero)
return n - c_rlpListStart; return n - c_rlpListStart;
else else
{ {
if ((int)m_data.size() <= n - c_rlpListIndLenZero) if (m_data.size() <= n - c_rlpListIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1) if (m_data.size() > 1)
if (m_data[1] == 0) if (m_data[1] == 0)
BOOST_THROW_EXCEPTION(BadRLP()); BOOST_THROW_EXCEPTION(BadRLP());
for (int i = 0; i < n - c_rlpListIndLenZero; ++i) if (n - c_rlpListIndLenZero > sizeof(ret))
// We did not check, but would most probably not fit in our memory.
BOOST_THROW_EXCEPTION(UndersizeRLP());
for (unsigned i = 0; i < n - c_rlpListIndLenZero; ++i)
ret = (ret << 8) | m_data[i + 1]; ret = (ret << 8) | m_data[i + 1];
} }
// We have to be able to add payloadOffset to length without overflow.
// This rejects roughly 4GB-sized RLPs on some platforms.
if (ret >= std::numeric_limits<size_t>::max() - 0x100)
BOOST_THROW_EXCEPTION(UndersizeRLP());
return ret; return ret;
} }
unsigned RLP::items() const size_t RLP::items() const
{ {
if (isList()) if (isList())
{ {
bytesConstRef d = payload().cropped(0, length()); bytesConstRef d = payload().cropped(0, length());
unsigned i = 0; size_t i = 0;
for (; d.size(); ++i) for (; d.size(); ++i)
d = d.cropped(RLP(d, ThrowOnFail | FailIfTooSmall).actualSize()); d = d.cropped(RLP(d, ThrowOnFail | FailIfTooSmall).actualSize());
return i; return i;
@ -200,14 +210,14 @@ unsigned RLP::items() const
return 0; return 0;
} }
RLPStream& RLPStream::appendRaw(bytesConstRef _s, unsigned _itemCount) RLPStream& RLPStream::appendRaw(bytesConstRef _s, size_t _itemCount)
{ {
m_out.insert(m_out.end(), _s.begin(), _s.end()); m_out.insert(m_out.end(), _s.begin(), _s.end());
noteAppended(_itemCount); noteAppended(_itemCount);
return *this; return *this;
} }
void RLPStream::noteAppended(unsigned _itemCount) void RLPStream::noteAppended(size_t _itemCount)
{ {
if (!_itemCount) if (!_itemCount)
return; return;
@ -223,7 +233,7 @@ void RLPStream::noteAppended(unsigned _itemCount)
{ {
auto p = m_listStack.back().second; auto p = m_listStack.back().second;
m_listStack.pop_back(); m_listStack.pop_back();
unsigned s = m_out.size() - p; // list size size_t s = m_out.size() - p; // list size
auto brs = bytesRequired(s); auto brs = bytesRequired(s);
unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs); unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
// cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")"; // cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")";
@ -232,19 +242,22 @@ void RLPStream::noteAppended(unsigned _itemCount)
memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p); memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p);
if (s < c_rlpListImmLenCount) if (s < c_rlpListImmLenCount)
m_out[p] = (byte)(c_rlpListStart + s); m_out[p] = (byte)(c_rlpListStart + s);
else else if (c_rlpListIndLenZero + brs <= 0xff)
{ {
m_out[p] = (byte)(c_rlpListIndLenZero + brs); m_out[p] = (byte)(c_rlpListIndLenZero + brs);
byte* b = &(m_out[p + brs]); byte* b = &(m_out[p + brs]);
for (; s; s >>= 8) for (; s; s >>= 8)
*(b--) = (byte)s; *(b--) = (byte)s;
} }
else
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large for RLP"));
} }
_itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list. _itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list.
} }
} }
RLPStream& RLPStream::appendList(unsigned _items) RLPStream& RLPStream::appendList(size_t _items)
{ {
// cdebug << "appendList(" << _items << ")"; // cdebug << "appendList(" << _items << ")";
if (_items) if (_items)
@ -266,10 +279,10 @@ RLPStream& RLPStream::appendList(bytesConstRef _rlp)
RLPStream& RLPStream::append(bytesConstRef _s, bool _compact) RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
{ {
unsigned s = _s.size(); size_t s = _s.size();
byte const* d = _s.data(); byte const* d = _s.data();
if (_compact) if (_compact)
for (unsigned i = 0; i < _s.size() && !*d; ++i, --s, ++d) {} for (size_t i = 0; i < _s.size() && !*d; ++i, --s, ++d) {}
if (s == 1 && *d < c_rlpDataImmLenStart) if (s == 1 && *d < c_rlpDataImmLenStart)
m_out.push_back(*d); m_out.push_back(*d);
@ -299,6 +312,8 @@ RLPStream& RLPStream::append(bigint _i)
else else
{ {
auto brbr = bytesRequired(br); auto brbr = bytesRequired(br);
if (c_rlpDataIndLenZero + brbr > 0xff)
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Number too large for RLP"));
m_out.push_back((byte)(c_rlpDataIndLenZero + brbr)); m_out.push_back((byte)(c_rlpDataIndLenZero + brbr));
pushInt(br, brbr); pushInt(br, brbr);
} }
@ -308,9 +323,11 @@ RLPStream& RLPStream::append(bigint _i)
return *this; return *this;
} }
void RLPStream::pushCount(unsigned _count, byte _base) void RLPStream::pushCount(size_t _count, byte _base)
{ {
auto br = bytesRequired(_count); auto br = bytesRequired(_count);
if (int(br) + _base > 0xff)
BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Count too large for RLP"));
m_out.push_back((byte)(br + _base)); // max 8 bytes. m_out.push_back((byte)(br + _base)); // max 8 bytes.
pushInt(_count, br); pushInt(_count, br);
} }

61
libdevcore/RLP.h

@ -113,12 +113,12 @@ public:
bool isInt() const; bool isInt() const;
/// @returns the number of items in the list, or zero if it isn't a list. /// @returns the number of items in the list, or zero if it isn't a list.
unsigned itemCount() const { return isList() ? items() : 0; } size_t itemCount() const { return isList() ? items() : 0; }
unsigned itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); } size_t itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); }
/// @returns the number of bytes in the data, or zero if it isn't data. /// @returns the number of bytes in the data, or zero if it isn't data.
unsigned size() const { return isData() ? length() : 0; } size_t size() const { return isData() ? length() : 0; }
unsigned sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); } size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); }
/// Equality operators; does best-effort conversion and checks for equality. /// Equality operators; does best-effort conversion and checks for equality.
bool operator==(char const* _s) const { return isData() && toString() == _s; } bool operator==(char const* _s) const { return isData() && toString() == _s; }
@ -137,7 +137,7 @@ public:
/// Subscript operator. /// Subscript operator.
/// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise.
/// @note if used to access items in ascending order, this is efficient. /// @note if used to access items in ascending order, this is efficient.
RLP operator[](unsigned _i) const; RLP operator[](size_t _i) const;
using element_type = RLP; using element_type = RLP;
@ -152,16 +152,16 @@ public:
iterator& operator++(); iterator& operator++();
iterator operator++(int) { auto ret = *this; operator++(); return ret; } iterator operator++(int) { auto ret = *this; operator++(); return ret; }
RLP operator*() const { return RLP(m_lastItem); } RLP operator*() const { return RLP(m_currentItem); }
bool operator==(iterator const& _cmp) const { return m_lastItem == _cmp.m_lastItem; } bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; }
bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); } bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); }
private: private:
iterator() {} iterator() {}
iterator(RLP const& _parent, bool _begin); iterator(RLP const& _parent, bool _begin);
unsigned m_remaining = 0; size_t m_remaining = 0;
bytesConstRef m_lastItem; bytesConstRef m_currentItem;
}; };
/// @brief Iterator into beginning of sub-item list (valid only if we are a list). /// @brief Iterator into beginning of sub-item list (valid only if we are a list).
@ -247,7 +247,7 @@ public:
if (itemCount() != N || !isList()) if (itemCount() != N || !isList())
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
std::array<T, N> ret; std::array<T, N> ret;
for (unsigned i = 0; i < N; ++i) for (size_t i = 0; i < N; ++i)
{ {
ret[i] = (T)operator[](i); ret[i] = (T)operator[](i);
} }
@ -259,19 +259,21 @@ public:
{ {
requireGood(); requireGood();
if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull()) if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
{
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
else else
return 0; return 0;
else {} }
auto p = payload(); auto p = payload();
if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig)) if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig))
{
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
else else
return 0; return 0;
else {} }
return fromBigEndian<_T>(p); return fromBigEndian<_T>(p);
} }
@ -280,14 +282,15 @@ public:
{ {
requireGood(); requireGood();
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall))) if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall)))
{
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast()); BOOST_THROW_EXCEPTION(BadCast());
else else
return _N(); return _N();
else{} }
_N ret; _N ret;
size_t s = std::min((size_t)_N::size, (size_t)length()); size_t s = std::min<size_t>(_N::size, length());
memcpy(ret.data() + _N::size - s, payload().data(), s); memcpy(ret.data() + _N::size - s, payload().data(), s);
return ret; return ret;
} }
@ -300,7 +303,7 @@ public:
/// @returns the theoretical size of this item. /// @returns the theoretical size of this item.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
unsigned actualSize() const; size_t actualSize() const;
private: private:
/// Disable construction from rvalue /// Disable construction from rvalue
@ -316,20 +319,20 @@ private:
unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; } unsigned lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }
/// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data. /// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data.
unsigned length() const; size_t length() const;
/// @returns the number of bytes into the data that the payload starts. /// @returns the number of bytes into the data that the payload starts.
unsigned payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); } size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); }
/// @returns the number of data items. /// @returns the number of data items.
unsigned items() const; size_t items() const;
/// Our byte data. /// Our byte data.
bytesConstRef m_data; bytesConstRef m_data;
/// The list-indexing cache. /// The list-indexing cache.
mutable unsigned m_lastIndex = (unsigned)-1; mutable size_t m_lastIndex = (size_t)-1;
mutable unsigned m_lastEnd = 0; mutable size_t m_lastEnd = 0;
mutable bytesConstRef m_lastItem; mutable bytesConstRef m_lastItem;
}; };
@ -343,7 +346,7 @@ public:
RLPStream() {} RLPStream() {}
/// Initializes the RLPStream as a list of @a _listItems items. /// Initializes the RLPStream as a list of @a _listItems items.
explicit RLPStream(unsigned _listItems) { appendList(_listItems); } explicit RLPStream(size_t _listItems) { appendList(_listItems); }
~RLPStream() {} ~RLPStream() {}
@ -359,7 +362,7 @@ public:
template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); } template <unsigned N> RLPStream& append(FixedHash<N> _s, bool _compact = false, bool _allOrNothing = false) { return _allOrNothing && !_s ? append(bytesConstRef()) : append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given. /// Appends an arbitrary RLP fragment - this *must* be a single item unless @a _itemCount is given.
RLPStream& append(RLP const& _rlp, unsigned _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); } RLPStream& append(RLP const& _rlp, size_t _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list. /// Appends a sequence of data to the stream as a list.
template <class _T> RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } template <class _T> RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); }
@ -370,14 +373,14 @@ public:
template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; } template <class T, class U> RLPStream& append(std::pair<T, U> const& _s) { appendList(2); append(_s.first); append(_s.second); return *this; }
/// Appends a list. /// Appends a list.
RLPStream& appendList(unsigned _items); RLPStream& appendList(size_t _items);
RLPStream& appendList(bytesConstRef _rlp); RLPStream& appendList(bytesConstRef _rlp);
RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); } RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); }
RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); } RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); }
/// Appends raw (pre-serialised) RLP data. Use with caution. /// Appends raw (pre-serialised) RLP data. Use with caution.
RLPStream& appendRaw(bytesConstRef _rlp, unsigned _itemCount = 1); RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, unsigned _itemCount = 1) { return appendRaw(&_rlp, _itemCount); } RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
/// Shift operators for appending data items. /// Shift operators for appending data items.
template <class T> RLPStream& operator<<(T _data) { return append(_data); } template <class T> RLPStream& operator<<(T _data) { return append(_data); }
@ -392,14 +395,14 @@ public:
void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); } void swapOut(bytes& _dest) { if(!m_listStack.empty()) BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("listStack is not empty")); swap(m_out, _dest); }
private: private:
void noteAppended(unsigned _itemCount = 1); void noteAppended(size_t _itemCount = 1);
/// Push the node-type byte (using @a _base) along with the item count @a _count. /// Push the node-type byte (using @a _base) along with the item count @a _count.
/// @arg _count is number of characters for strings, data-bytes for ints, or items for lists. /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists.
void pushCount(unsigned _count, byte _offset); void pushCount(size_t _count, byte _offset);
/// Push an integer as a raw big-endian byte-stream. /// Push an integer as a raw big-endian byte-stream.
template <class _T> void pushInt(_T _i, unsigned _br) template <class _T> void pushInt(_T _i, size_t _br)
{ {
m_out.resize(m_out.size() + _br); m_out.resize(m_out.size() + _br);
byte* b = &m_out.back(); byte* b = &m_out.back();
@ -410,7 +413,7 @@ private:
/// Our output byte stream. /// Our output byte stream.
bytes m_out; bytes m_out;
std::vector<std::pair<unsigned, unsigned>> m_listStack; std::vector<std::pair<size_t, size_t>> m_listStack;
}; };
template <class _T> void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } template <class _T> void rlpListAux(RLPStream& _out, _T _t) { _out << _t; }

2
libethereum/Transaction.cpp

@ -42,7 +42,7 @@ std::ostream& dev::eth::operator<<(std::ostream& _out, ExecutionResult const& _e
TransactionException dev::eth::toTransactionException(Exception const& _e) TransactionException dev::eth::toTransactionException(Exception const& _e)
{ {
// Basic Transaction exceptions // Basic Transaction exceptions
if (!!dynamic_cast<BadRLP const*>(&_e)) if (!!dynamic_cast<RLPException const*>(&_e))
return TransactionException::BadRLP; return TransactionException::BadRLP;
if (!!dynamic_cast<OutOfGasIntrinsic const*>(&_e)) if (!!dynamic_cast<OutOfGasIntrinsic const*>(&_e))
return TransactionException::OutOfGasIntrinsic; return TransactionException::OutOfGasIntrinsic;

Loading…
Cancel
Save