diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index 92d97aec4..cf4218050 100644 --- a/libdevcore/RLP.cpp +++ b/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(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(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::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); } diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index 67f464b9d..1586616d8 100644 --- a/libdevcore/RLP.h +++ b/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 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(_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 RLPStream& append(FixedHash _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 RLPStream& append(std::vector<_T> const& _s) { return appendVector(_s); } @@ -370,14 +373,14 @@ public: template RLPStream& append(std::pair 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 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 void pushInt(_T _i, unsigned _br) + template 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> m_listStack; + std::vector> m_listStack; }; template void rlpListAux(RLPStream& _out, _T _t) { _out << _t; } diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index 70f82c6d2..b634ef1d3 100644 --- a/libethereum/Transaction.cpp +++ b/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(&_e)) + if (!!dynamic_cast(&_e)) return TransactionException::BadRLP; if (!!dynamic_cast(&_e)) return TransactionException::OutOfGasIntrinsic;