Control flow analysis for inline assembly.

This commit is contained in:
Daniel Kirchner
2020-03-09 16:23:10 +01:00
parent b7c001eb7f
commit 809e3503ba
29 changed files with 526 additions and 46 deletions
@@ -0,0 +1,11 @@
contract C {
function f() public pure {
assembly {
function f() {
// Make sure this doesn't trigger the unimplemented assertion in the control flow builder.
leave
}
}
}
}
// ----
@@ -0,0 +1,10 @@
contract C {
function f() public pure {
assembly {
// Make sure this doesn't trigger the unimplemented assertion in the control flow builder.
leave
}
}
}
// ----
// SyntaxError: (178-183): Keyword "leave" can only be used inside a function.
@@ -0,0 +1,29 @@
contract C {
struct S { bool f; }
S s;
function f() internal pure returns (S storage c) {
assembly {
for {} eq(0,0) { c_slot := s_slot } {}
}
}
function g() internal pure returns (S storage c) {
assembly {
for {} eq(0,1) { c_slot := s_slot } {}
}
}
function h() internal pure returns (S storage c) {
assembly {
for {} eq(0,0) {} { c_slot := s_slot }
}
}
function i() internal pure returns (S storage c) {
assembly {
for {} eq(0,1) {} { c_slot := s_slot }
}
}
}
// ----
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
// TypeError: (228-239): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
// TypeError: (369-380): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
// TypeError: (510-521): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,15 @@
contract C {
struct S { bool f; }
S s;
function f() internal pure returns (S storage c) {
assembly {
for { c_slot := s_slot } iszero(0) {} {}
}
}
function g() internal pure returns (S storage c) {
assembly {
for { c_slot := s_slot } iszero(1) {} {}
}
}
}
// ----
@@ -0,0 +1,11 @@
contract C {
struct S { bool f; }
S s;
function f(bool flag) internal pure returns (S storage c) {
assembly {
if flag { c_slot := s_slot }
}
}
}
// ----
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,13 @@
contract C {
struct S { bool f; }
S s;
function f() internal pure returns (S storage c) {
// this should warn about unreachable code, but currently function flow is ignored
assembly {
function f() { return(0, 0) }
f()
c_slot := s_slot
}
}
}
// ----
@@ -0,0 +1,13 @@
contract C {
struct S { bool f; }
S s;
function f() internal pure returns (S storage c) {
// this could be allowed, but currently control flow for functions is not analysed
assembly {
function f() { revert(0, 0) }
f()
}
}
}
// ----
// TypeError: (87-98): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,10 @@
contract C {
struct S { bool f; }
S s;
function f() internal pure returns (S storage c) {
assembly {
c_slot := s_slot
}
}
}
// ----
@@ -0,0 +1,27 @@
contract C {
struct S { bool f; }
S s;
function f(uint256 a) internal pure returns (S storage c) {
assembly {
switch a
case 0 { c_slot := s_slot }
}
}
function g(bool flag) internal pure returns (S storage c) {
assembly {
switch flag
case 0 { c_slot := s_slot }
case 1 { c_slot := s_slot }
}
}
function h(uint256 a) internal pure returns (S storage c) {
assembly {
switch a
case 0 { c_slot := s_slot }
default { return(0,0) }
}
}
}
// ----
// TypeError: (96-107): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
// TypeError: (256-267): This variable is of storage pointer type and can be returned without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,25 @@
contract C {
struct S { bool f; }
S s;
function f(uint256 a) internal pure returns (S storage c) {
assembly {
switch a
default { c_slot := s_slot }
}
}
function g(bool flag) internal pure returns (S storage c) {
assembly {
switch flag
case 0 { c_slot := s_slot }
default { c_slot := s_slot }
}
}
function h(uint256 a) internal pure returns (S storage c) {
assembly {
switch a
case 0 { revert(0, 0) }
default { c_slot := s_slot }
}
}
}
// ----
@@ -6,4 +6,4 @@ contract C {
}
}
// ----
// TypeError: (92-116): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
// TypeError: (107-113): This variable is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour.
@@ -0,0 +1,17 @@
contract C {
function f() public pure {
assembly {
revert(0, 0)
revert(0, 0)
}
}
function g() public pure {
assembly {
revert(0, 0)
}
revert();
}
}
// ----
// Warning: (100-112): Unreachable code.
// Warning: (222-230): Unreachable code.
@@ -0,0 +1,13 @@
contract C {
function f() public pure {
assembly {
for { let a := 0} lt(a,1) { a := add(a, 1) } {
break
let b := 42
}
}
}
}
// ----
// Warning: (103-117): Unreachable code.
// Warning: (160-171): Unreachable code.
@@ -0,0 +1,12 @@
contract C {
function f() public pure {
assembly {
for { let a := 0} lt(a,1) { a := add(a, 1) } {
continue
let b := 42
}
}
}
}
// ----
// Warning: (163-174): Unreachable code.
@@ -0,0 +1,17 @@
contract C {
function f(uint256 y) public pure returns (uint256 x) {
assembly {
return(0, 0)
x := y
}
}
function g(uint256 y) public pure returns (uint256 x) {
assembly {
return(0, 0)
}
x = y;
}
}
// ----
// Warning: (129-135): Unreachable code.
// Warning: (274-279): Unreachable code.
@@ -0,0 +1,17 @@
contract C {
function f(uint256 y) public pure returns (uint256 x) {
assembly {
revert(0, 0)
x := y
}
}
function g(uint256 y) public pure returns (uint256 x) {
assembly {
revert(0, 0)
}
x = y;
}
}
// ----
// Warning: (129-135): Unreachable code.
// Warning: (274-279): Unreachable code.
+1 -1
View File
@@ -539,7 +539,7 @@ BOOST_AUTO_TEST_CASE(builtins_analysis)
{
return _name == "builtin"_yulstring ? &f : nullptr;
}
BuiltinFunction f{"builtin"_yulstring, vector<Type>(2), vector<Type>(3), {}};
BuiltinFunction f{"builtin"_yulstring, vector<Type>(2), vector<Type>(3), {}, {}};
};
SimpleDialect dialect;