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: | ||||
|  * 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. | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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() | ||||
| 
 | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user