mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2564 from ethereum/large-arrays-calldata
Add type error for arrays too large for calldata
This commit is contained in:
commit
556ddd0f38
@ -3,7 +3,8 @@
|
|||||||
Features:
|
Features:
|
||||||
* Inline Assembly: Show useful error message if trying to access calldata variables.
|
* Inline Assembly: Show useful error message if trying to access calldata variables.
|
||||||
* Inline Assembly: Support variable declaration without initial value (defaults to 0).
|
* 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:
|
Bugfixes:
|
||||||
* Type Checker: Fix invalid "specify storage keyword" warning for reference members of structs.
|
* Type Checker: Fix invalid "specify storage keyword" warning for reference members of structs.
|
||||||
|
@ -583,6 +583,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
|||||||
!FunctionType(_variable).interfaceFunctionType()
|
!FunctionType(_variable).interfaceFunctionType()
|
||||||
)
|
)
|
||||||
m_errorReporter.typeError(_variable.location(), "Internal type is not allowed for public state variables.");
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1395,12 +1395,23 @@ bool ArrayType::operator==(Type const& _other) const
|
|||||||
return isDynamicallySized() || length() == other.length();
|
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())
|
if (isDynamicallySized())
|
||||||
return 32;
|
return 32;
|
||||||
bigint size = bigint(length()) * (isByteArray() ? 1 : baseType()->calldataEncodedSize(_padded));
|
bigint size = bigint(length()) * (isByteArray() ? 1 : baseType()->calldataEncodedSize(_padded));
|
||||||
size = ((size + 31) / 32) * 32;
|
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.");
|
solAssert(size <= numeric_limits<unsigned>::max(), "Array size does not fit unsigned.");
|
||||||
return unsigned(size);
|
return unsigned(size);
|
||||||
}
|
}
|
||||||
|
@ -616,6 +616,9 @@ public:
|
|||||||
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
virtual TypePointer interfaceType(bool _inLibrary) const override;
|
||||||
virtual bool canBeUsedExternally(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
|
/// @returns true if this is a byte array or a string
|
||||||
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
bool isByteArray() const { return m_arrayKind != ArrayKind::Ordinary; }
|
||||||
/// @returns true if this is a string
|
/// @returns true if this is a string
|
||||||
@ -630,6 +633,8 @@ private:
|
|||||||
/// String is interpreted as a subtype of Bytes.
|
/// String is interpreted as a subtype of Bytes.
|
||||||
enum class ArrayKind { Ordinary, Bytes, String };
|
enum class ArrayKind { Ordinary, Bytes, String };
|
||||||
|
|
||||||
|
bigint unlimitedCalldataEncodedSize(bool _padded) const;
|
||||||
|
|
||||||
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
///< Byte arrays ("bytes") and strings have different semantics from ordinary arrays.
|
||||||
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
ArrayKind m_arrayKind = ArrayKind::Ordinary;
|
||||||
TypePointer m_baseType;
|
TypePointer m_baseType;
|
||||||
|
@ -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.");
|
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()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user