Skip to content

Commit ef64a12

Browse files
authored
Merge pull request #837 from crytic/dev-unchecked-block
Add checked arithmetic + unchecked block
2 parents bd91f39 + 55962d4 commit ef64a12

File tree

127 files changed

+59
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

127 files changed

+59
-3
lines changed

slither/slithir/operations/binary.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ def get_type(operation_type): # pylint: disable=too-many-branches
8888

8989
raise SlithIRError("get_type: Unknown operation type {})".format(operation_type))
9090

91+
def can_be_checked_for_overflow(self):
92+
return self in [
93+
BinaryType.POWER,
94+
BinaryType.MULTIPLICATION,
95+
BinaryType.MODULO,
96+
BinaryType.ADDITION,
97+
BinaryType.SUBTRACTION,
98+
BinaryType.DIVISION,
99+
]
100+
91101
def __str__(self): # pylint: disable=too-many-branches
92102
if self == BinaryType.POWER:
93103
return "**"
@@ -167,6 +177,8 @@ def type(self):
167177

168178
@property
169179
def type_str(self):
180+
if self.node.scope.is_checked and self._type.can_be_checked_for_overflow():
181+
return "(c)" + str(self._type)
170182
return str(self._type)
171183

172184
def __str__(self):

slither/solc_parsing/declarations/function.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,8 @@ def _parse_statement(
931931
node = self._parse_for(statement, node)
932932
elif name == "Block":
933933
node = self._parse_block(statement, node)
934+
elif name == "UncheckedBlock":
935+
node = self._parse_unchecked_block(statement, node)
934936
elif name == "InlineAssembly":
935937
# Added with solc 0.6 - the yul code is an AST
936938
if "AST" in statement and not self.compilation_unit.core.skip_assembly:
@@ -1015,7 +1017,7 @@ def _parse_statement(
10151017

10161018
return node
10171019

1018-
def _parse_block(self, block: Dict, node: NodeSolc):
1020+
def _parse_block(self, block: Dict, node: NodeSolc, check_arithmetic: bool = False):
10191021
"""
10201022
Return:
10211023
Node
@@ -1027,7 +1029,25 @@ def _parse_block(self, block: Dict, node: NodeSolc):
10271029
else:
10281030
statements = block[self.get_children("children")]
10291031

1030-
new_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
1032+
check_arithmetic = check_arithmetic | node.underlying_node.scope.is_checked
1033+
new_scope = Scope(check_arithmetic, False, node.underlying_node.scope)
1034+
for statement in statements:
1035+
node = self._parse_statement(statement, node, new_scope)
1036+
return node
1037+
1038+
def _parse_unchecked_block(self, block: Dict, node: NodeSolc):
1039+
"""
1040+
Return:
1041+
Node
1042+
"""
1043+
assert block[self.get_key()] == "UncheckedBlock"
1044+
1045+
if self.is_compact_ast:
1046+
statements = block["statements"]
1047+
else:
1048+
statements = block[self.get_children("children")]
1049+
1050+
new_scope = Scope(False, False, node.underlying_node.scope)
10311051
for statement in statements:
10321052
node = self._parse_statement(statement, node, new_scope)
10331053
return node
@@ -1048,7 +1068,8 @@ def _parse_cfg(self, cfg: Dict):
10481068
self._function.is_empty = True
10491069
else:
10501070
self._function.is_empty = False
1051-
self._parse_block(cfg, node)
1071+
check_arithmetic = self.compilation_unit.solc_version >= "0.8.0"
1072+
self._parse_block(cfg, node, check_arithmetic=check_arithmetic)
10521073
self._remove_incorrect_edges()
10531074
self._remove_alone_endif()
10541075

830 Bytes
Binary file not shown.
831 Bytes
Binary file not shown.
905 Bytes
Binary file not shown.
905 Bytes
Binary file not shown.
964 Bytes
Binary file not shown.
974 Bytes
Binary file not shown.
961 Bytes
Binary file not shown.
972 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)