diff --git a/Changelog.md b/Changelog.md index a20a9a980..af09f8045 100644 --- a/Changelog.md +++ b/Changelog.md @@ -10,11 +10,13 @@ Bugfixes: * Code Generator: Do not include internal functions in the runtime bytecode which are only referenced in the constructor. * Code Generator: Properly skip unneeded storage array cleanup when not reducing length. * Code Generator: Bugfix in modifier lookup in libraries. + * Code Generator: Implement packed encoding of external function types. * Commandline interface: Support ``--evm-version constantinople`` properly. * DocString Parser: Fix error message for empty descriptions. * Standard JSON: Support ``constantinople`` as ``evmVersion`` properly. * Type System: Improve error message when attempting to shift by a fractional amount. * Type System: Make external library functions accessible. + * Type System: Prevent encoding of weird types. ### 0.4.21 (2018-03-07) diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 6e287f838..620dfca48 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -1644,9 +1644,20 @@ bool TypeChecker::visit(FunctionCall const& _functionCall) auto const& argType = type(*arguments[i]); if (functionType->takesArbitraryParameters()) { + bool errored = false; if (auto t = dynamic_cast(argType.get())) if (!t->mobileType()) + { m_errorReporter.typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero)."); + errored = true; + } + if (!errored && !( + argType->mobileType() && + argType->mobileType()->interfaceType(false) && + argType->mobileType()->interfaceType(false)->encodingType() && + !(dynamic_cast(argType->mobileType()->interfaceType(false)->encodingType().get())) + )) + m_errorReporter.typeError(arguments[i]->location(), "This type cannot be encoded."); } else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i])) m_errorReporter.typeError( diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 720215c90..4c462d098 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1262,6 +1262,8 @@ bool ContractType::isPayable() const TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const { + if (isSuper()) + return TypePointer{}; return _operator == Token::Delete ? make_shared() : TypePointer(); } diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index c930dd240..b7e648918 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -692,22 +692,27 @@ public: virtual bool operator==(Type const& _other) const override; virtual unsigned calldataEncodedSize(bool _padded ) const override { + solAssert(!isSuper(), ""); return encodingType()->calldataEncodedSize(_padded); } - virtual unsigned storageBytes() const override { return 20; } - virtual bool canLiveOutsideStorage() const override { return true; } + virtual unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; } + virtual bool canLiveOutsideStorage() const override { return !isSuper(); } virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; } - virtual bool isValueType() const override { return true; } + virtual bool isValueType() const override { return !isSuper(); } virtual std::string toString(bool _short) const override; virtual std::string canonicalName() const override; virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; virtual TypePointer encodingType() const override { + if (isSuper()) + return TypePointer{}; return std::make_shared(160, IntegerType::Modifier::Address); } virtual TypePointer interfaceType(bool _inLibrary) const override { + if (isSuper()) + return TypePointer{}; return _inLibrary ? shared_from_this() : encodingType(); } diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp index 68f0b3a11..676d5d4e3 100644 --- a/libsolidity/codegen/CompilerUtils.cpp +++ b/libsolidity/codegen/CompilerUtils.cpp @@ -142,7 +142,6 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound dynamic_cast(_type).kind() == FunctionType::Kind::External ) { - solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented."); combineExternalFunctionType(true); m_context << Instruction::DUP2 << Instruction::MSTORE; m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index a866e46c3..f5813aed1 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2077,6 +2077,31 @@ BOOST_AUTO_TEST_CASE(packed_keccak256) testContractAgainstCpp("a(bytes32)", f, u256(-1)); } +BOOST_AUTO_TEST_CASE(packed_keccak256_complex_types) +{ + char const* sourceCode = R"( + contract test { + uint120[3] x; + function f() view returns (bytes32 hash1, bytes32 hash2, bytes32 hash3) { + uint120[] memory y = new uint120[](3); + x[0] = y[0] = uint120(-2); + x[1] = y[1] = uint120(-3); + x[2] = y[2] = uint120(-4); + hash1 = keccak256(x); + hash2 = keccak256(y); + hash3 = keccak256(this.f); + } + } + )"; + compileAndRun(sourceCode); + // Strangely, arrays are encoded with intra-element padding. + ABI_CHECK(callContractFunction("f()"), encodeArgs( + dev::keccak256(encodeArgs(u256("0xfffffffffffffffffffffffffffffe"), u256("0xfffffffffffffffffffffffffffffd"), u256("0xfffffffffffffffffffffffffffffc"))), + dev::keccak256(encodeArgs(u256("0xfffffffffffffffffffffffffffffe"), u256("0xfffffffffffffffffffffffffffffd"), u256("0xfffffffffffffffffffffffffffffc"))), + dev::keccak256(fromHex(m_contractAddress.hex() + "26121ff0")) + )); +} + BOOST_AUTO_TEST_CASE(packed_sha256) { char const* sourceCode = R"( diff --git a/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_internal_functions.sol b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_internal_functions.sol new file mode 100644 index 000000000..9f57c3a4a --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_internal_functions.sol @@ -0,0 +1,11 @@ +contract C { + function f() public pure { + bytes32 h = keccak256(keccak256, f, this.f.gas, block.blockhash); + h; + } +} +// ---- +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_special_types.sol b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_special_types.sol new file mode 100644 index 000000000..a7d13215b --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_special_types.sol @@ -0,0 +1,13 @@ +contract C { + function f() public pure { + bool a = address(this).call(address(this).delegatecall, super); + bool b = address(this).delegatecall(log0, tx, mulmod); + a; b; + } +} +// ---- +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_structs.sol b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_structs.sol new file mode 100644 index 000000000..f27290fdc --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_structs.sol @@ -0,0 +1,13 @@ +contract C { + struct S { uint x; } + S s; + struct T { } + T t; + function f() public pure { + bytes32 a = sha256(s, t); + a; + } +} +// ---- +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_types.sol b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_types.sol new file mode 100644 index 000000000..991b2237a --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/types_with_unspecified_encoding_types.sol @@ -0,0 +1,16 @@ +contract C { + struct S { uint x; } + S s; + struct T { } + T t; + enum A { X, Y } + function f() public pure { + bool a = address(this).delegatecall(S, A, A.X, T, uint, uint[]); + } +} +// ---- +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. +// TypeError: This type cannot be encoded. diff --git a/test/libsolidity/syntaxTests/specialFunctions/types_without_encoding_problems.sol b/test/libsolidity/syntaxTests/specialFunctions/types_without_encoding_problems.sol new file mode 100644 index 000000000..c83645486 --- /dev/null +++ b/test/libsolidity/syntaxTests/specialFunctions/types_without_encoding_problems.sol @@ -0,0 +1,9 @@ +contract C { + uint[3] sarr; + function f() view public { + uint[3] memory arr; + bytes32 h = keccak256(this.f, arr, sarr); + h; + } +} +// ----