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: 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)
|
||||
|
||||
|
@ -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<RationalNumberType const*>(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<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]))
|
||||
m_errorReporter.typeError(
|
||||
|
@ -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<TupleType>() : TypePointer();
|
||||
}
|
||||
|
||||
|
@ -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<IntegerType>(160, IntegerType::Modifier::Address);
|
||||
}
|
||||
virtual TypePointer interfaceType(bool _inLibrary) const override
|
||||
{
|
||||
if (isSuper())
|
||||
return TypePointer{};
|
||||
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
|
||||
)
|
||||
{
|
||||
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;
|
||||
|
@ -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"(
|
||||
|
@ -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