Skip to content

Commit c9f772e

Browse files
authored
Merge pull request #13299 from ethereum/fix-bad-cast-tuple-returned-from-function-abi-encodeCall
Fix bad_cast when abi.encodeCall() receives a tuple expression
2 parents 82e5a11 + 9acf693 commit c9f772e

18 files changed

+250
-2
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Compiler Features:
1313
Bugfixes:
1414
* Commandline Interface: Disallow the following options outside of the compiler mode: ``--via-ir``,``--metadata-literal``, ``--metadata-hash``, ``--model-checker-show-unproved``, ``--model-checker-div-mod-no-slacks``, ``--model-checker-engine``, ``--model-checker-invariants``, ``--model-checker-solvers``, ``--model-checker-timeout``, ``--model-checker-contracts``, ``--model-checker-targets``.
1515
* Type Checker: Fix null dereference in `abi.encodeCall` type checking of free function.
16+
* Type Checker: Fix compiler crash when `abi.encodeCall` received a tuple expression instead of an inline tuple.
1617

1718

1819
### 0.8.15 (2022-06-15)

libsolidity/analysis/TypeChecker.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,8 +2248,17 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
22482248
auto const* tupleType = dynamic_cast<TupleType const*>(type(*arguments[1]));
22492249
if (tupleType)
22502250
{
2251-
auto const& argumentTuple = dynamic_cast<TupleExpression const&>(*arguments[1].get());
2252-
callArguments = decltype(callArguments){argumentTuple.components().begin(), argumentTuple.components().end()};
2251+
if (TupleExpression const* argumentTuple = dynamic_cast<TupleExpression const*>(arguments[1].get()))
2252+
callArguments = decltype(callArguments){argumentTuple->components().begin(), argumentTuple->components().end()};
2253+
else
2254+
{
2255+
m_errorReporter.typeError(
2256+
9062_error,
2257+
arguments[1]->location(),
2258+
"Expected an inline tuple, not an expression of a tuple type."
2259+
);
2260+
return;
2261+
}
22532262
}
22542263
else
22552264
callArguments.push_back(arguments[1]);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
contract C {
2+
function g0() internal pure {}
3+
function g2() internal pure returns (uint, uint) { return (2, 3); }
4+
5+
function f0() public {}
6+
function f2(uint, uint) public {}
7+
8+
function h() public view {
9+
uint a;
10+
uint b;
11+
12+
abi.encodeCall(this.f0, () = g0());
13+
abi.encodeCall(this.f0, () = ());
14+
abi.encodeCall(this.f2, (a, b) = g2());
15+
abi.encodeCall(this.f2, (a, b) = (2, 3));
16+
}
17+
}
18+
// ----
19+
// TypeError 5547: (284-286): Empty tuple on the left hand side.
20+
// TypeError 9062: (284-293): Expected an inline tuple, not an expression of a tuple type.
21+
// TypeError 5547: (328-330): Empty tuple on the left hand side.
22+
// TypeError 9062: (328-335): Expected an inline tuple, not an expression of a tuple type.
23+
// TypeError 9062: (370-383): Expected an inline tuple, not an expression of a tuple type.
24+
// TypeError 9062: (418-433): Expected an inline tuple, not an expression of a tuple type.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
contract C {
2+
function g0() internal pure {}
3+
function g2() internal pure returns (uint, uint) { return (2, 3); }
4+
5+
function f0() public {}
6+
function f2(uint, uint) public {}
7+
8+
function h() public view {
9+
abi.encodeCall(this.f0, true ? g0() : g0());
10+
abi.encodeCall(this.f2, true ? g2() : g2());
11+
abi.encodeCall(this.f2, true ? (1, 2) : (3, 4));
12+
}
13+
}
14+
// ----
15+
// TypeError 9062: (251-269): Expected an inline tuple, not an expression of a tuple type.
16+
// TypeError 9062: (304-322): Expected an inline tuple, not an expression of a tuple type.
17+
// TypeError 9062: (357-379): Expected an inline tuple, not an expression of a tuple type.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
contract C {
2+
event Ev();
3+
error Er();
4+
5+
function f0() public {}
6+
7+
function h() public view {
8+
abi.encodeCall(this.f0, Ev());
9+
abi.encodeCall(this.f0, Er());
10+
abi.encodeCall(this.f0, revert());
11+
}
12+
}
13+
// ----
14+
// TypeError 9062: (138-142): Expected an inline tuple, not an expression of a tuple type.
15+
// TypeError 9062: (177-181): Expected an inline tuple, not an expression of a tuple type.
16+
// TypeError 9062: (216-224): Expected an inline tuple, not an expression of a tuple type.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
contract C {
2+
event Ev();
3+
error Er();
4+
5+
function g0() internal pure {}
6+
function g2() internal pure returns (uint, uint) { return (2, 3); }
7+
8+
function f0() public {}
9+
function f2(uint, uint) public {}
10+
11+
function h() public view {
12+
abi.encodeCall(this.f2, (1, 1) + (2, 2));
13+
abi.encodeCall(this.f0, Ev() / Er());
14+
abi.encodeCall(this.f0, !());
15+
}
16+
}
17+
// ----
18+
// TypeError 2271: (284-299): Operator + not compatible with types tuple(int_const 1,int_const 1) and tuple(int_const 2,int_const 2)
19+
// TypeError 9062: (284-299): Expected an inline tuple, not an expression of a tuple type.
20+
// TypeError 2271: (334-345): Operator / not compatible with types tuple() and tuple()
21+
// TypeError 9062: (334-345): Expected an inline tuple, not an expression of a tuple type.
22+
// TypeError 4907: (380-383): Unary operator ! cannot be applied to type tuple()
23+
// TypeError 9062: (380-383): Expected an inline tuple, not an expression of a tuple type.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
contract C {
2+
function g0() internal pure {}
3+
function g2() internal pure returns (uint, uint) { return (2, 3); }
4+
5+
function f0() public {}
6+
function f2(uint, uint) public {}
7+
8+
function h() public view {
9+
abi.encodeCall(this.f0, g0());
10+
abi.encodeCall(this.f2, g2());
11+
12+
abi.encodeCall(this.f0, (g0()));
13+
abi.encodeCall(this.f2, (g2()));
14+
}
15+
}
16+
// ----
17+
// TypeError 9062: (251-255): Expected an inline tuple, not an expression of a tuple type.
18+
// TypeError 9062: (290-294): Expected an inline tuple, not an expression of a tuple type.
19+
// TypeError 6473: (331-335): Tuple component cannot be empty.
20+
// TypeError 7788: (306-337): Expected 0 instead of 1 components for the tuple parameter.
21+
// TypeError 7788: (347-378): Expected 2 instead of 1 components for the tuple parameter.
22+
// TypeError 5407: (372-376): Cannot implicitly convert component at position 0 from "tuple(uint256,uint256)" to "uint256".
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
contract C {
2+
function g1() internal pure returns (uint) { return (1); }
3+
4+
function f1(uint) public {}
5+
6+
function h() public view {
7+
uint a;
8+
9+
abi.encodeCall(this.f1, (a) = g1());
10+
abi.encodeCall(this.f1, (a) = (1));
11+
}
12+
}
13+
// ----
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
contract C {
2+
function g1() internal pure returns (uint) { return (1); }
3+
4+
function f1(uint) public {}
5+
6+
function h() public view {
7+
abi.encodeCall(this.f1, true ? (1) : (2));
8+
abi.encodeCall(this.f1, true ? g1() : g1());
9+
}
10+
}
11+
// ----
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
contract C {
2+
function g1() internal pure returns (uint) { return (1); }
3+
function g2() internal pure returns (uint, uint) { return (2, 3); }
4+
5+
function f1(uint) public {}
6+
function f2(uint, uint) public {}
7+
8+
function h() public view {
9+
abi.encodeCall(this.f1, g1());
10+
abi.encodeCall(this.f1, (g1()));
11+
abi.encodeCall(this.f2, (g1(), g1()));
12+
}
13+
}
14+
// ----

0 commit comments

Comments
 (0)