aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-07-14 05:07:34 +0800
committerGitHub <noreply@github.com>2017-07-14 05:07:34 +0800
commit556ddd0f381f532d322758e3e00485055e7d1ed0 (patch)
treecb96bf31298c1fd0c77ee9ab41299b23cfe52475
parent63bf0f68e6d232eccf6d64ca2bba5b39e108ea41 (diff)
parent4229caaadc1767571806a11ea431c5cf389081ac (diff)
downloaddexon-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.md3
-rw-r--r--libsolidity/analysis/TypeChecker.cpp10
-rw-r--r--libsolidity/ast/Types.cpp13
-rw-r--r--libsolidity/ast/Types.h5
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp25
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()
}