mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
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:
commit
58c57e446b
@ -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)
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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"(
|
||||||
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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.
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
Loading…
Reference in New Issue
Block a user