diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2017-07-14 05:07:34 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-14 05:07:34 +0800 |
commit | 556ddd0f381f532d322758e3e00485055e7d1ed0 (patch) | |
tree | cb96bf31298c1fd0c77ee9ab41299b23cfe52475 | |
parent | 63bf0f68e6d232eccf6d64ca2bba5b39e108ea41 (diff) | |
parent | 4229caaadc1767571806a11ea431c5cf389081ac (diff) | |
download | dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar.gz dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar.bz2 dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar.lz dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar.xz dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.tar.zst dexon-solidity-556ddd0f381f532d322758e3e00485055e7d1ed0.zip |
Merge pull request #2564 from ethereum/large-arrays-calldata
Add type error for arrays too large for calldata
-rw-r--r-- | Changelog.md | 3 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 10 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 13 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 5 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 25 |
5 files changed, 54 insertions, 2 deletions
diff --git a/Changelog.md b/Changelog.md index 139238fd..62b52942 100644 --- a/Changelog.md +++ b/Changelog.md @@ -3,7 +3,8 @@ Features: * Inline Assembly: Show useful error message if trying to access calldata variables. * Inline Assembly: Support variable declaration without initial value (defaults to 0). - * Type Checker: Disallow value transfers to contracts without a payable fallback function + * Type Checker: Disallow value transfers to contracts without a payable fallback function. + * Type Checker: Raise proper error for arrays too large for ABI encoding. Bugfixes: * Type Checker: Fix invalid "specify storage keyword" warning for reference members of structs. diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 4e5a11ed..29db7441 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -583,6 +583,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable) !FunctionType(_variable).interfaceFunctionType() ) m_errorReporter.typeError(_variable.location(), "Internal type is not allowed for public state variables."); + + if (varType->category() == Type::Category::Array) + if (auto arrayType = dynamic_cast<ArrayType const*>(varType.get())) + if ( + ((arrayType->location() == DataLocation::Memory) || + (arrayType->location() == DataLocation::CallData)) && + !arrayType->validForCalldata() + ) + m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded as calldata."); + return false; } diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index b54407c6..76bfb1a8 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1395,12 +1395,23 @@ bool ArrayType::operator==(Type const& _other) const return isDynamicallySized() || length() == other.length(); } -unsigned ArrayType::calldataEncodedSize(bool _padded) const +bool ArrayType::validForCalldata() const +{ + return unlimitedCalldataEncodedSize(true) <= numeric_limits<unsigned>::max(); +} + +bigint ArrayType::unlimitedCalldataEncodedSize(bool _padded) const { if (isDynamicallySized()) return 32; bigint size = bigint(length()) * (isByteArray() ? 1 : baseType()->calldataEncodedSize(_padded)); size = ((size + 31) / 32) * 32; + return size; +} + +unsigned ArrayType::calldataEncodedSize(bool _padded) const +{ + bigint size = unlimitedCalldataEncodedSize(_padded); solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned."); return unsigned(size); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index bd5da30a..c24cc11a 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -616,6 +616,9 @@ public: virtual TypePointer interfaceType(bool _inLibrary) const override; virtual bool canBeUsedExternally(bool _inLibrary) const override; + /// @returns true if this is valid to be stored in calldata + bool validForCalldata() const; + /// @returns true if this is a byte array or a string bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; } /// @returns true if this is a string @@ -630,6 +633,8 @@ private: /// String is interpreted as a subtype of Bytes. enum class ArrayKind { Ordinary, Bytes, String }; + bigint unlimitedCalldataEncodedSize(bool _padded) const; + ///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays. ArrayKind m_arrayKind = ArrayKind::Ordinary; TypePointer m_baseType; diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 472f1b97..36b48cfd 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -6297,6 +6297,31 @@ BOOST_AUTO_TEST_CASE(implicit_conversion_disallowed) CHECK_ERROR(text, TypeError, "Return argument type uint32 is not implicitly convertible to expected type (type of first return variable) bytes4."); } +BOOST_AUTO_TEST_CASE(too_large_arrays_for_calldata) +{ + char const* text = R"( + contract C { + function f(uint[85678901234] a) external { + } + } + )"; + CHECK_ERROR(text, TypeError, "Array is too large to be encoded as calldata."); + text = R"( + contract C { + function f(uint[85678901234] a) internal { + } + } + )"; + CHECK_SUCCESS_NO_WARNINGS(text); + text = R"( + contract C { + function f(uint[85678901234] a) { + } + } + )"; + CHECK_ERROR(text, TypeError, "Array is too large to be encoded as calldata."); +} + BOOST_AUTO_TEST_SUITE_END() } |