Merge pull request #3753 from ethereum/whoSupportsPackedEncoding

Prevent encoding of weird types and support packed encoding of extenal function types.
This commit is contained in:
Alex Beregszaszi 2018-03-29 11:24:51 +01:00 committed by GitHub
commit 58c57e446b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 110 additions and 4 deletions

View File

@ -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: 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: Properly skip unneeded storage array cleanup when not reducing length.
* Code Generator: Bugfix in modifier lookup in libraries. * Code Generator: Bugfix in modifier lookup in libraries.
* Code Generator: Implement packed encoding of external function types.
* Commandline interface: Support ``--evm-version constantinople`` properly. * Commandline interface: Support ``--evm-version constantinople`` properly.
* DocString Parser: Fix error message for empty descriptions. * DocString Parser: Fix error message for empty descriptions.
* Standard JSON: Support ``constantinople`` as ``evmVersion`` properly. * Standard JSON: Support ``constantinople`` as ``evmVersion`` properly.
* Type System: Improve error message when attempting to shift by a fractional amount. * Type System: Improve error message when attempting to shift by a fractional amount.
* Type System: Make external library functions accessible. * Type System: Make external library functions accessible.
* Type System: Prevent encoding of weird types.
### 0.4.21 (2018-03-07) ### 0.4.21 (2018-03-07)

View File

@ -1644,9 +1644,20 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
auto const& argType = type(*arguments[i]); auto const& argType = type(*arguments[i]);
if (functionType->takesArbitraryParameters()) if (functionType->takesArbitraryParameters())
{ {
bool errored = false;
if (auto t = dynamic_cast<RationalNumberType const*>(argType.get())) if (auto t = dynamic_cast<RationalNumberType const*>(argType.get()))
if (!t->mobileType()) if (!t->mobileType())
{
m_errorReporter.typeError(arguments[i]->location(), "Invalid rational number (too large or division by zero)."); 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<StructType const*>(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])) else if (!type(*arguments[i])->isImplicitlyConvertibleTo(*parameterTypes[i]))
m_errorReporter.typeError( m_errorReporter.typeError(

View File

@ -1262,6 +1262,8 @@ bool ContractType::isPayable() const
TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const TypePointer ContractType::unaryOperatorResult(Token::Value _operator) const
{ {
if (isSuper())
return TypePointer{};
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer(); return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
} }

View File

@ -692,22 +692,27 @@ public:
virtual bool operator==(Type const& _other) const override; virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded ) const override virtual unsigned calldataEncodedSize(bool _padded ) const override
{ {
solAssert(!isSuper(), "");
return encodingType()->calldataEncodedSize(_padded); return encodingType()->calldataEncodedSize(_padded);
} }
virtual unsigned storageBytes() const override { return 20; } virtual unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
virtual bool canLiveOutsideStorage() const override { return true; } virtual bool canLiveOutsideStorage() const override { return !isSuper(); }
virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; } 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 toString(bool _short) const override;
virtual std::string canonicalName() const override; virtual std::string canonicalName() const override;
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override; virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
virtual TypePointer encodingType() const override virtual TypePointer encodingType() const override
{ {
if (isSuper())
return TypePointer{};
return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address); return std::make_shared<IntegerType>(160, IntegerType::Modifier::Address);
} }
virtual TypePointer interfaceType(bool _inLibrary) const override virtual TypePointer interfaceType(bool _inLibrary) const override
{ {
if (isSuper())
return TypePointer{};
return _inLibrary ? shared_from_this() : encodingType(); return _inLibrary ? shared_from_this() : encodingType();
} }

View File

@ -142,7 +142,6 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
dynamic_cast<FunctionType const&>(_type).kind() == FunctionType::Kind::External dynamic_cast<FunctionType const&>(_type).kind() == FunctionType::Kind::External
) )
{ {
solUnimplementedAssert(_padToWordBoundaries, "Non-padded store for function not implemented.");
combineExternalFunctionType(true); combineExternalFunctionType(true);
m_context << Instruction::DUP2 << Instruction::MSTORE; m_context << Instruction::DUP2 << Instruction::MSTORE;
m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD; m_context << u256(_padToWordBoundaries ? 32 : 24) << Instruction::ADD;

View File

@ -2077,6 +2077,31 @@ BOOST_AUTO_TEST_CASE(packed_keccak256)
testContractAgainstCpp("a(bytes32)", f, u256(-1)); 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) BOOST_AUTO_TEST_CASE(packed_sha256)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

View File

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

View File

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

View File

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

View File

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

View File

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