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)
{
m_lastItem.retarget(m_lastItem.next().data(), m_remaining);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining -= std::min<unsigned>(m_remaining, m_lastItem.size());
m_currentItem.retarget(m_currentItem.next().data(), m_remaining);
m_currentItem = m_currentItem.cropped(0, RLP(m_currentItem, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining -= std::min<size_t>(m_remaining, m_currentItem.size());
}
else
m_lastItem.retarget(m_lastItem.next().data(), 0);
m_currentItem.retarget(m_currentItem.next().data(), 0);
return *this;
}
@ -63,17 +63,17 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
if (_begin && _parent.isList())
{
auto pl = _parent.payload();
m_lastItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining = pl.size() - m_lastItem.size();
m_currentItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize());
m_remaining = pl.size() - m_currentItem.size();
}
else
{
m_lastItem = _parent.data().cropped(_parent.data().size());
m_currentItem = _parent.data().cropped(_parent.data().size());
m_remaining = 0;
}
}
RLP RLP::operator[](unsigned _i) const
RLP RLP::operator[](size_t _i) const
{
if (_i < m_lastIndex)
{
@ -100,7 +100,7 @@ RLPs RLP::toList() const
return ret;
}
unsigned RLP::actualSize() const
size_t RLP::actualSize() const
{
if (isNull())
return 0;
@ -142,7 +142,7 @@ bool RLP::isInt() const
}
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());
return m_data[1 + n - c_rlpDataIndLenZero] != 0;
}
@ -151,48 +151,58 @@ bool RLP::isInt() const
return false;
}
unsigned RLP::length() const
size_t RLP::length() const
{
if (isNull())
return 0;
requireGood();
unsigned ret = 0;
byte n = m_data[0];
size_t ret = 0;
byte const n = m_data[0];
if (n < c_rlpDataImmLenStart)
return 1;
else if (n <= c_rlpDataIndLenZero)
return n - c_rlpDataImmLenStart;
else if (n < c_rlpListStart)
{
if ((int)m_data.size() <= n - c_rlpDataIndLenZero)
if (m_data.size() <= n - c_rlpDataIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1)
if (m_data.size() > 1)
if (m_data[1] == 0)
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];
}
else if (n <= c_rlpListIndLenZero)
return n - c_rlpListStart;
else
{
if ((int)m_data.size() <= n - c_rlpListIndLenZero)
if (m_data.size() <= n - c_rlpListIndLenZero)
BOOST_THROW_EXCEPTION(BadRLP());
if ((int)m_data.size() > 1)
if (m_data.size() > 1)
if (m_data[1] == 0)
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];
}
// 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;
}
unsigned RLP::items() const
size_t RLP::items() const
{
if (isList())
{
bytesConstRef d = payload().cropped(0, length());
unsigned i = 0;
size_t i = 0;
for (; d.size(); ++i)
d = d.cropped(RLP(d, ThrowOnFail | FailIfTooSmall).actualSize());
return i;
@ -200,14 +210,14 @@ unsigned RLP::items() const
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());
noteAppended(_itemCount);
return *this;
}
void RLPStream::noteAppended(unsigned _itemCount)
void RLPStream::noteAppended(size_t _itemCount)
{
if (!_itemCount)
return;
@ -223,7 +233,7 @@ void RLPStream::noteAppended(unsigned _itemCount)
{
auto p = m_listStack.back().second;
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);
unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + 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);
if (s < c_rlpListImmLenCount)
m_out[p] = (byte)(c_rlpListStart + s);
else
else if (c_rlpListIndLenZero + brs <= 0xff)
{
m_out[p] = (byte)(c_rlpListIndLenZero + brs);
byte* b = &(m_out[p + brs]);
for (; s; s >>= 8)
*(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.
}
}
RLPStream& RLPStream::appendList(unsigned _items)
RLPStream& RLPStream::appendList(size_t _items)
{
// cdebug << "appendList(" << _items << ")";
if (_items)
@ -266,10 +279,10 @@ RLPStream& RLPStream::appendList(bytesConstRef _rlp)
RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
{
unsigned s = _s.size();
size_t s = _s.size();
byte const* d = _s.data();
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)
m_out.push_back(*d);
@ -299,6 +312,8 @@ RLPStream& RLPStream::append(bigint _i)
else
{
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));
pushInt(br, brbr);
}
@ -308,9 +323,11 @@ RLPStream& RLPStream::append(bigint _i)
return *this;
}
void RLPStream::pushCount(unsigned _count, byte _base)
void RLPStream::pushCount(size_t _count, byte _base)
{
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.
pushInt(_count, br);
}

61
libdevcore/RLP.h

@ -113,12 +113,12 @@ public:
bool isInt() const;
/// @returns the number of items in the list, or zero if it isn't a list.
unsigned itemCount() const { return isList() ? items() : 0; }
unsigned itemCountStrict() const { if (!isList()) BOOST_THROW_EXCEPTION(BadCast()); return items(); }
size_t itemCount() const { return isList() ? items() : 0; }
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.
unsigned size() const { return isData() ? length() : 0; }
unsigned sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); }
size_t size() const { return isData() ? length() : 0; }
size_t sizeStrict() const { if (!isData()) BOOST_THROW_EXCEPTION(BadCast()); return length(); }
/// Equality operators; does best-effort conversion and checks for equality.
bool operator==(char const* _s) const { return isData() && toString() == _s; }
@ -137,7 +137,7 @@ public:
/// Subscript operator.
/// @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.
RLP operator[](unsigned _i) const;
RLP operator[](size_t _i) const;
using element_type = RLP;
@ -152,16 +152,16 @@ public:
iterator& operator++();
iterator operator++(int) { auto ret = *this; operator++(); return ret; }
RLP operator*() const { return RLP(m_lastItem); }
bool operator==(iterator const& _cmp) const { return m_lastItem == _cmp.m_lastItem; }
RLP operator*() const { return RLP(m_currentItem); }
bool operator==(iterator const& _cmp) const { return m_currentItem == _cmp.m_currentItem; }
bool operator!=(iterator const& _cmp) const { return !operator==(_cmp); }
private:
iterator() {}
iterator(RLP const& _parent, bool _begin);
unsigned m_remaining = 0;
bytesConstRef m_lastItem;
size_t m_remaining = 0;
bytesConstRef m_currentItem;
};
/// @brief Iterator into beginning of sub-item list (valid only if we are a list).
@ -247,7 +247,7 @@ public:
if (itemCount() != N || !isList())
BOOST_THROW_EXCEPTION(BadCast());
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);
}
@ -259,19 +259,21 @@ public:
{
requireGood();
if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
{
if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast());
else
return 0;
else {}
}
auto p = payload();
if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig))
{
if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast());
else
return 0;
else {}
}
return fromBigEndian<_T>(p);
}
@ -280,14 +282,15 @@ public:
{
requireGood();
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)) || (length() < _N::size && (_flags & FailIfTooSmall)))
{
if (_flags & ThrowOnFail)
BOOST_THROW_EXCEPTION(BadCast());
else
return _N();
else{}
}
_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);
return ret;
}
@ -300,7 +303,7 @@ public:
/// @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.
unsigned actualSize() const;
size_t actualSize() const;
private:
/// 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; }
/// @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.
unsigned payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); }
size_t payloadOffset() const { return isSingleByte() ? 0 : (1 + lengthSize()); }
/// @returns the number of data items.
unsigned items() const;
size_t items() const;
/// Our byte data.
bytesConstRef m_data;
/// The list-indexing cache.
mutable unsigned m_lastIndex = (unsigned)-1;
mutable unsigned m_lastEnd = 0;
mutable size_t m_lastIndex = (size_t)-1;
mutable size_t m_lastEnd = 0;
mutable bytesConstRef m_lastItem;
};
@ -343,7 +346,7 @@ public:
RLPStream() {}
/// Initializes the RLPStream as a list of @a _listItems items.
explicit RLPStream(unsigned _listItems) { appendList(_listItems); }
explicit RLPStream(size_t _listItems) { appendList(_listItems); }
~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); }
/// 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.
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; }
/// Appends a list.
RLPStream& appendList(unsigned _items);
RLPStream& appendList(size_t _items);
RLPStream& appendList(bytesConstRef _rlp);
RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); }
RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); }
/// Appends raw (pre-serialised) RLP data. Use with caution.
RLPStream& appendRaw(bytesConstRef _rlp, unsigned _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, unsigned _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
RLPStream& appendRaw(bytesConstRef _rlp, size_t _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, size_t _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
/// Shift operators for appending data items.
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); }
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.
/// @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.
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);
byte* b = &m_out.back();
@ -410,7 +413,7 @@ private:
/// Our output byte stream.
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; }

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)
{
// Basic Transaction exceptions
if (!!dynamic_cast<BadRLP const*>(&_e))
if (!!dynamic_cast<RLPException const*>(&_e))
return TransactionException::BadRLP;
if (!!dynamic_cast<OutOfGasIntrinsic const*>(&_e))
return TransactionException::OutOfGasIntrinsic;

Loading…
Cancel
Save