Issue error properly for oversized arrays for calldata

This commit is contained in:
Alex Beregszaszi 2017-07-11 21:56:09 +01:00
parent 63bf0f68e6
commit cb4875a28b
4 changed files with 25 additions and 2 deletions

View File

@ -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.

View File

@ -583,6 +583,12 @@ 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::CallData) && !arrayType->validForCalldata())
m_errorReporter.typeError(_variable.location(), "Array is too large to be encoded as calldata.");
return false; return false;
} }

View File

@ -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);
} }

View File

@ -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;