Merge pull request #14367 from ethereum/functionTypeMobileType

Restrict mobile types of function types.
This commit is contained in:
Nikola Matić 2023-07-18 17:55:02 +02:00 committed by GitHub
commit 23fb9bc3a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 170 additions and 43 deletions

View File

@ -30,6 +30,7 @@ Bugfixes:
* SMTChecker: Fix false negative when a verification target can be violated only by trusted external call from another public function.
* SMTChecker: Fix internal error caused by using external identifier to encode member access to functions that take an internal function as a parameter.
* Standard JSON Interface: Fix an incomplete AST being returned when analysis is interrupted by certain kinds of fatal errors.
* Type Checker: Disallow using certain unassignable function types in complex expressions.
* Type Checker: Function declaration types referring to different declarations are no longer convertible to each other.
* Yul Optimizer: Ensure that the assignment of memory slots for variables moved to memory does not depend on AST IDs that may depend on whether additional files are included during compilation.
* Yul Optimizer: Fix ``FullInliner`` step not ignoring code that is not in expression-split form.

View File

@ -3423,11 +3423,9 @@ MemberList::MemberMap FunctionType::nativeMembers(ASTNode const* _scope) const
}
case Kind::DelegateCall:
{
auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration);
solAssert(functionDefinition, "");
solAssert(functionDefinition->visibility() != Visibility::Private, "");
if (functionDefinition->visibility() != Visibility::Internal)
if (auto const* functionDefinition = dynamic_cast<FunctionDefinition const*>(m_declaration))
{
solAssert(functionDefinition->visibility() > Visibility::Internal, "");
auto const *contract = dynamic_cast<ContractDefinition const*>(m_declaration->scope());
solAssert(contract, "");
solAssert(contract->isLibrary(), "");
@ -3472,7 +3470,11 @@ Type const* FunctionType::mobileType() const
if (valueSet() || gasSet() || saltSet() || hasBoundFirstArgument())
return nullptr;
// return function without parameter names
// Special function types do not get a mobile type, such that they cannot be used in complex expressions.
if (m_kind != FunctionType::Kind::Internal && m_kind != FunctionType::Kind::External && m_kind != FunctionType::Kind::DelegateCall)
return nullptr;
// return function without parameter names and without declaration
return TypeProvider::function(
m_parameterTypes,
m_returnParameterTypes,
@ -3480,7 +3482,7 @@ Type const* FunctionType::mobileType() const
strings(m_returnParameterNames.size()),
m_kind,
m_stateMutability,
m_declaration,
nullptr,
Options::fromFunctionType(*this)
);
}

View File

@ -0,0 +1,10 @@
contract C {
function f() public {}
function g() public {}
function h(bool c) public returns (bytes4) {
return (c ? this.f : this.g).selector;
}
}
// ----
// h(bool): true -> 0x26121ff000000000000000000000000000000000000000000000000000000000
// h(bool): false -> 0xe2179b8e00000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1,19 @@
contract A {
function f() public {}
function g() public {}
}
contract C {
A a = new A();
function getContract() public view returns (A) {
return a;
}
function test(bool b) public view returns (bytes4) {
return (b ? getContract().f : getContract().g).selector;
}
}
// ----
// test(bool): true -> 0x26121ff000000000000000000000000000000000000000000000000000000000
// test(bool): false -> 0xe2179b8e00000000000000000000000000000000000000000000000000000000

View File

@ -0,0 +1,10 @@
contract C {
function f() internal pure returns(uint256) { return 1;}
function g() internal pure returns(uint256) { return 2; }
function test(bool b) public returns(uint256) {
return (b ? C.f : C.g)();
}
}
// ----
// test(bool): true -> 1
// test(bool): false -> 2

View File

@ -0,0 +1,13 @@
library L {
function f() internal pure returns(uint256){ return 1; }
}
contract C {
function g() internal pure returns(uint256) { return 2; }
function test(bool b) public returns(uint256) {
return (b ? L.f : C.g)();
}
}
// ----
// test(bool): true -> 1
// test(bool): false -> 2

View File

@ -0,0 +1,10 @@
contract C {
function f() public pure returns(uint256) { return 1; }
function g() public pure returns(uint256) { return 2; }
function test(bool b) public returns(uint256) {
return (b ? C.f : C.g)();
}
}
// ----
// test(bool): true -> 1
// test(bool): false -> 2

View File

@ -0,0 +1,11 @@
error MyCustomError(uint, bool);
contract C {
function f() pure public {
true ? MyCustomError : MyCustomError;
}
}
// ----
// TypeError 9717: (93-106): Invalid mobile type in true expression.
// TypeError 3703: (109-122): Invalid mobile type in false expression.

View File

@ -1,18 +0,0 @@
error MyCustomError(uint, bool);
error MyCustomError2(uint, bool);
error MyCustomError3(uint, bool, bool);
contract C {
function f() pure public {
true ? MyCustomError : MyCustomError;
true ? MyCustomError : MyCustomError2;
true ? MyCustomError : MyCustomError3;
true ? MyCustomError : true;
true ? true : MyCustomError;
}
}
// ----
// TypeError 1080: (253-290): True expression's type error MyCustomError(uint256,bool) does not match false expression's type error MyCustomError3(uint256,bool,bool).
// TypeError 1080: (300-327): True expression's type error MyCustomError(uint256,bool) does not match false expression's type bool.
// TypeError 1080: (337-364): True expression's type bool does not match false expression's type error MyCustomError(uint256,bool).

View File

@ -0,0 +1,10 @@
contract C {
event MyCustomEvent(uint);
function f() pure public {
true ? MyCustomEvent : MyCustomEvent;
}
}
// ----
// TypeError 9717: (90-103): Invalid mobile type in true expression.
// TypeError 3703: (106-119): Invalid mobile type in false expression.

View File

@ -1,17 +0,0 @@
contract C {
event MyCustomEvent(uint);
event MyCustomEvent2(uint);
event MyCustomEvent3(uint, bool);
function f() pure public {
true ? MyCustomEvent : MyCustomEvent;
true ? MyCustomEvent : MyCustomEvent2;
true ? MyCustomEvent : MyCustomEvent3;
true ? MyCustomEvent : true;
true ? true : MyCustomEvent;
}
}
// ----
// TypeError 1080: (246-283): True expression's type event MyCustomEvent(uint256) does not match false expression's type event MyCustomEvent3(uint256,bool).
// TypeError 1080: (293-320): True expression's type event MyCustomEvent(uint256) does not match false expression's type bool.
// TypeError 1080: (330-357): True expression's type bool does not match false expression's type event MyCustomEvent(uint256).

View File

@ -8,4 +8,5 @@ contract C {
}
}
// ----
// TypeError 1080: (117-130): True expression's type function D.f() does not match false expression's type function D.g().
// TypeError 9717: (121-124): Invalid mobile type in true expression.
// TypeError 3703: (127-130): Invalid mobile type in false expression.

View File

@ -0,0 +1,8 @@
contract C {
function f() public pure returns (uint x) {
x = (true ? addmod : addmod)(3, 4, 5);
}
}
// ----
// TypeError 9717: (81-87): Invalid mobile type in true expression.
// TypeError 3703: (90-96): Invalid mobile type in false expression.

View File

@ -0,0 +1,10 @@
contract C {
function f() external pure { }
function g() external pure { }
function test(bool b) public returns(bytes4) {
(b ? C.f : C.g).selector;
}
}
// ----
// TypeError 9717: (147-150): Invalid mobile type in true expression.
// TypeError 3703: (153-156): Invalid mobile type in false expression.

View File

@ -0,0 +1,13 @@
contract C {
function f() public pure { }
function g() public pure { }
}
contract A {
function test(bool b) public returns(bytes4) {
(b ? C.f : C.g).selector;
}
}
// ----
// TypeError 9717: (159-162): Invalid mobile type in true expression.
// TypeError 3703: (165-168): Invalid mobile type in false expression.

View File

@ -0,0 +1,16 @@
contract C {
function f() external pure { }
}
contract D {
function g() external pure { }
}
contract A {
function test(bool b) public returns(bytes4) {
(b ? C.f : D.g).selector;
}
}
// ----
// TypeError 9717: (179-182): Invalid mobile type in true expression.
// TypeError 3703: (185-188): Invalid mobile type in false expression.

View File

@ -0,0 +1,16 @@
interface I1 {
function f() external pure;
}
interface I2 {
function g() external pure;
}
contract C {
function test(bool b) public returns(bytes4) {
(b ? I1.f : I2.g).selector;
}
}
// ----
// TypeError 9717: (177-181): Invalid mobile type in true expression.
// TypeError 3703: (184-188): Invalid mobile type in false expression.

View File

@ -0,0 +1,12 @@
library L {
function f() external {}
}
contract C {
function test() public {
(true ? L.f : L.f).selector;
}
}
// ----
// TypeError 9582: (94-121): Member "selector" not found or not visible after argument-dependent lookup in function ().