From 65497ece537c6c270064de04bb0d7c8e40b1aa9e Mon Sep 17 00:00:00 2001 From: Josselin Date: Wed, 28 Apr 2021 14:45:46 +0200 Subject: [PATCH] minor --- slither/core/cfg/scope.py | 8 +- slither/core/declarations/contract.py | 20 +++- slither/core/declarations/function.py | 4 +- slither/slithir/operations/binary.py | 3 +- slither/solc_parsing/declarations/function.py | 108 +++++++++++++----- slither/solc_parsing/declarations/modifier.py | 4 +- slither/solc_parsing/yul/parse_yul.py | 71 +++++++++--- 7 files changed, 161 insertions(+), 57 deletions(-) diff --git a/slither/core/cfg/scope.py b/slither/core/cfg/scope.py index 95816a8be..06e68c3e9 100644 --- a/slither/core/cfg/scope.py +++ b/slither/core/cfg/scope.py @@ -5,10 +5,10 @@ if TYPE_CHECKING: from slither.core.declarations.function import Function +# pylint: disable=too-few-public-methods class Scope: - - def __init__(self, is_checked:bool, is_yul: bool, scope: Union["Scope", "Function"]): - self.nodes: List[Node] = [] + def __init__(self, is_checked: bool, is_yul: bool, scope: Union["Scope", "Function"]): + self.nodes: List["Node"] = [] self.is_checked = is_checked self.is_yul = is_yul - self.father = scope \ No newline at end of file + self.father = scope diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index f614c3f4b..a1230135d 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -1115,12 +1115,16 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods constructor_variable.set_offset(self.source_mapping, self.compilation_unit) self._functions[constructor_variable.canonical_name] = constructor_variable - prev_node = self._create_node(constructor_variable, 0, variable_candidate, constructor_variable) + prev_node = self._create_node( + constructor_variable, 0, variable_candidate, constructor_variable + ) variable_candidate.node_initialization = prev_node counter = 1 for v in self.state_variables[idx + 1 :]: if v.expression and not v.is_constant: - next_node = self._create_node(constructor_variable, counter, v, prev_node.scope) + next_node = self._create_node( + constructor_variable, counter, v, prev_node.scope + ) v.node_initialization = next_node prev_node.add_son(next_node) next_node.add_father(prev_node) @@ -1143,12 +1147,16 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods constructor_variable.set_offset(self.source_mapping, self.compilation_unit) self._functions[constructor_variable.canonical_name] = constructor_variable - prev_node = self._create_node(constructor_variable, 0, variable_candidate, constructor_variable) + prev_node = self._create_node( + constructor_variable, 0, variable_candidate, constructor_variable + ) variable_candidate.node_initialization = prev_node counter = 1 for v in self.state_variables[idx + 1 :]: if v.expression and v.is_constant: - next_node = self._create_node(constructor_variable, counter, v, prev_node.scope) + next_node = self._create_node( + constructor_variable, counter, v, prev_node.scope + ) v.node_initialization = next_node prev_node.add_son(next_node) next_node.add_father(prev_node) @@ -1157,7 +1165,9 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods break - def _create_node(self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]): + def _create_node( + self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function] + ): from slither.core.cfg.node import Node, NodeType from slither.core.expressions import ( AssignmentOperationType, diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 85ba5497d..70639c169 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -1531,7 +1531,9 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods ################################################################################### ################################################################################### - def new_node(self, node_type: "NodeType", src: Union[str, Dict], scope: Union[Scope, "Function"]) -> "Node": + def new_node( + self, node_type: "NodeType", src: Union[str, Dict], scope: Union[Scope, "Function"] + ) -> "Node": from slither.core.cfg.node import Node node = Node(node_type, self._counter_nodes, scope) diff --git a/slither/slithir/operations/binary.py b/slither/slithir/operations/binary.py index c3464564e..cf76132a1 100644 --- a/slither/slithir/operations/binary.py +++ b/slither/slithir/operations/binary.py @@ -131,7 +131,7 @@ class BinaryType(Enum): class Binary(OperationWithLValue): - def __init__(self, result, left_variable, right_variable, operation_type: BinaryType, is_checked: bool=False): + def __init__(self, result, left_variable, right_variable, operation_type: BinaryType): assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function) assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function) assert is_valid_lvalue(result) @@ -144,7 +144,6 @@ class Binary(OperationWithLValue): result.set_type(ElementaryType("bool")) else: result.set_type(left_variable.type) - self.is_checked = is_checked @property def read(self): diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index eb6f63bd4..151a58a18 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -329,13 +329,17 @@ class FunctionSolc: ################################################################################### ################################################################################### - def _new_node(self, node_type: NodeType, src: Union[str, Dict], scope: Union[Scope, "Function"]) -> NodeSolc: + def _new_node( + self, node_type: NodeType, src: Union[str, Dict], scope: Union[Scope, "Function"] + ) -> NodeSolc: node = self._function.new_node(node_type, src, scope) node_parser = NodeSolc(node) self._node_to_nodesolc[node] = node_parser return node_parser - def _new_yul_block(self, src: Union[str, Dict], father_scope: Union[Scope, Function]) -> YulBlock: + def _new_yul_block( + self, src: Union[str, Dict], father_scope: Union[Scope, Function] + ) -> YulBlock: scope = Scope(False, True, father_scope) node = self._function.new_node(NodeType.ASSEMBLY, src, scope) contract = None @@ -366,26 +370,42 @@ class FunctionSolc: condition = if_statement["condition"] # Note: check if the expression could be directly # parsed here - condition_node = self._new_node(NodeType.IF, condition["src"], node.underlying_node.scope) + condition_node = self._new_node( + NodeType.IF, condition["src"], node.underlying_node.scope + ) condition_node.add_unparsed_expression(condition) link_underlying_nodes(node, condition_node) - true_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) - trueStatement = self._parse_statement(if_statement["trueBody"], condition_node, true_scope) + true_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) + trueStatement = self._parse_statement( + if_statement["trueBody"], condition_node, true_scope + ) if "falseBody" in if_statement and if_statement["falseBody"]: - false_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) - falseStatement = self._parse_statement(if_statement["falseBody"], condition_node, false_scope) + false_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) + falseStatement = self._parse_statement( + if_statement["falseBody"], condition_node, false_scope + ) else: children = if_statement[self.get_children("children")] condition = children[0] # Note: check if the expression could be directly # parsed here - condition_node = self._new_node(NodeType.IF, condition["src"], node.underlying_node.scope) + condition_node = self._new_node( + NodeType.IF, condition["src"], node.underlying_node.scope + ) condition_node.add_unparsed_expression(condition) link_underlying_nodes(node, condition_node) - true_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) + true_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) trueStatement = self._parse_statement(children[1], condition_node, true_scope) if len(children) == 3: - false_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) + false_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) falseStatement = self._parse_statement(children[2], condition_node, false_scope) endIf_node = self._new_node(NodeType.ENDIF, if_statement["src"], node.underlying_node.scope) @@ -400,21 +420,29 @@ class FunctionSolc: def _parse_while(self, whilte_statement: Dict, node: NodeSolc) -> NodeSolc: # WhileStatement = 'while' '(' Expression ')' Statement - node_startWhile = self._new_node(NodeType.STARTLOOP, whilte_statement["src"], node.underlying_node.scope) + node_startWhile = self._new_node( + NodeType.STARTLOOP, whilte_statement["src"], node.underlying_node.scope + ) body_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) if self.is_compact_ast: - node_condition = self._new_node(NodeType.IFLOOP, whilte_statement["condition"]["src"], node.underlying_node.scope) + node_condition = self._new_node( + NodeType.IFLOOP, whilte_statement["condition"]["src"], node.underlying_node.scope + ) node_condition.add_unparsed_expression(whilte_statement["condition"]) statement = self._parse_statement(whilte_statement["body"], node_condition, body_scope) else: children = whilte_statement[self.get_children("children")] expression = children[0] - node_condition = self._new_node(NodeType.IFLOOP, expression["src"], node.underlying_node.scope) + node_condition = self._new_node( + NodeType.IFLOOP, expression["src"], node.underlying_node.scope + ) node_condition.add_unparsed_expression(expression) statement = self._parse_statement(children[1], node_condition, body_scope) - node_endWhile = self._new_node(NodeType.ENDLOOP, whilte_statement["src"], node.underlying_node.scope) + node_endWhile = self._new_node( + NodeType.ENDLOOP, whilte_statement["src"], node.underlying_node.scope + ) link_underlying_nodes(node, node_startWhile) link_underlying_nodes(node_startWhile, node_condition) @@ -550,8 +578,12 @@ class FunctionSolc: else: pre, cond, post, body = self._parse_for_legacy_ast(statement) - node_startLoop = self._new_node(NodeType.STARTLOOP, statement["src"], node.underlying_node.scope) - node_endLoop = self._new_node(NodeType.ENDLOOP, statement["src"], node.underlying_node.scope) + node_startLoop = self._new_node( + NodeType.STARTLOOP, statement["src"], node.underlying_node.scope + ) + node_endLoop = self._new_node( + NodeType.ENDLOOP, statement["src"], node.underlying_node.scope + ) last_scope = node.underlying_node.scope @@ -597,13 +629,21 @@ class FunctionSolc: def _parse_dowhile(self, do_while_statement: Dict, node: NodeSolc) -> NodeSolc: - node_startDoWhile = self._new_node(NodeType.STARTLOOP, do_while_statement["src"], node.underlying_node.scope) - condition_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) + node_startDoWhile = self._new_node( + NodeType.STARTLOOP, do_while_statement["src"], node.underlying_node.scope + ) + condition_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) if self.is_compact_ast: - node_condition = self._new_node(NodeType.IFLOOP, do_while_statement["condition"]["src"], condition_scope) + node_condition = self._new_node( + NodeType.IFLOOP, do_while_statement["condition"]["src"], condition_scope + ) node_condition.add_unparsed_expression(do_while_statement["condition"]) - statement = self._parse_statement(do_while_statement["body"], node_condition, condition_scope) + statement = self._parse_statement( + do_while_statement["body"], node_condition, condition_scope + ) else: children = do_while_statement[self.get_children("children")] # same order in the AST as while @@ -633,7 +673,9 @@ class FunctionSolc: if externalCall is None: raise ParsingError("Try/Catch not correctly parsed by Slither %s" % statement) - catch_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope) + catch_scope = Scope( + node.underlying_node.scope.is_checked, False, node.underlying_node.scope + ) new_node = self._new_node(NodeType.TRY, statement["src"], catch_scope) new_node.add_unparsed_expression(externalCall) link_underlying_nodes(node, new_node) @@ -675,7 +717,9 @@ class FunctionSolc: self._add_local_variable(local_var_parser) # local_var.analyze(self) - new_node = self._new_node(NodeType.VARIABLE, statement["src"], node.underlying_node.scope) + new_node = self._new_node( + NodeType.VARIABLE, statement["src"], node.underlying_node.scope + ) new_node.underlying_node.add_variable_declaration(local_var) link_underlying_nodes(node, new_node) return new_node @@ -758,7 +802,9 @@ class FunctionSolc: "typeDescriptions": {"typeString": "tuple()"}, } node = new_node - new_node = self._new_node(NodeType.EXPRESSION, statement["src"], node.underlying_node.scope) + new_node = self._new_node( + NodeType.EXPRESSION, statement["src"], node.underlying_node.scope + ) new_node.add_unparsed_expression(expression) link_underlying_nodes(node, new_node) @@ -838,7 +884,9 @@ class FunctionSolc: ], } node = new_node - new_node = self._new_node(NodeType.EXPRESSION, statement["src"], node.underlying_node.scope) + new_node = self._new_node( + NodeType.EXPRESSION, statement["src"], node.underlying_node.scope + ) new_node.add_unparsed_expression(expression) link_underlying_nodes(node, new_node) @@ -860,7 +908,9 @@ class FunctionSolc: link_underlying_nodes(node, new_node) return new_node - def _parse_statement(self, statement: Dict, node: NodeSolc, scope: Union[Scope, Function]) -> NodeSolc: + def _parse_statement( + self, statement: Dict, node: NodeSolc, scope: Union[Scope, Function] + ) -> NodeSolc: """ Return: @@ -1146,7 +1196,9 @@ class FunctionSolc: for m in ExportValues(m).result(): if isinstance(m, Function): - node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"], self.underlying_function) + node_parser = self._new_node( + NodeType.EXPRESSION, modifier["src"], self.underlying_function + ) node_parser.add_unparsed_expression(modifier) # The latest entry point is the entry point, or the latest modifier call if self._function.modifiers: @@ -1163,7 +1215,9 @@ class FunctionSolc: ) elif isinstance(m, Contract): - node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"], self.underlying_function) + node_parser = self._new_node( + NodeType.EXPRESSION, modifier["src"], self.underlying_function + ) node_parser.add_unparsed_expression(modifier) # The latest entry point is the entry point, or the latest constructor call if self._function.explicit_base_constructor_calls_statements: diff --git a/slither/solc_parsing/declarations/modifier.py b/slither/solc_parsing/declarations/modifier.py index 0c14045ee..3fdc22d4e 100644 --- a/slither/solc_parsing/declarations/modifier.py +++ b/slither/solc_parsing/declarations/modifier.py @@ -93,7 +93,9 @@ class ModifierSolc(FunctionSolc): # self._analyze_read_write() # self._analyze_calls() - def _parse_statement(self, statement: Dict, node: NodeSolc, scope: Union[Scope, "Function"]) -> NodeSolc: + def _parse_statement( + self, statement: Dict, node: NodeSolc, scope: Union[Scope, "Function"] + ) -> NodeSolc: name = statement[self.get_key()] if name == "PlaceholderStatement": placeholder_node = self._new_node(NodeType.PLACEHOLDER, statement["src"], scope) diff --git a/slither/solc_parsing/yul/parse_yul.py b/slither/solc_parsing/yul/parse_yul.py index d8c32a4b8..b07053378 100644 --- a/slither/solc_parsing/yul/parse_yul.py +++ b/slither/solc_parsing/yul/parse_yul.py @@ -200,7 +200,9 @@ class YulLocalVariable: # pylint: disable=too-few-public-methods class YulFunction(YulScope): __slots__ = ["_function", "_root", "_ast", "_nodes", "_entrypoint", "node_scope"] - def __init__(self, func: Function, root: YulScope, ast: Dict, node_scope: Union[Function, Scope]): + def __init__( + self, func: Function, root: YulScope, ast: Dict, node_scope: Union[Function, Scope] + ): super().__init__(root.contract, root.id + [ast["name"]], parent_func=root.parent_func) assert ast["nodeType"] == "YulFunctionDefinition" @@ -277,7 +279,14 @@ class YulBlock(YulScope): __slots__ = ["_entrypoint", "_parent_func", "_nodes", "node_scope"] - def __init__(self, contract: Optional[Contract], entrypoint: Node, yul_id: List[str], node_scope: Union[Scope, Function], **kwargs): + def __init__( + self, + contract: Optional[Contract], + entrypoint: Node, + yul_id: List[str], + node_scope: Union[Scope, Function], + **kwargs, + ): super().__init__(contract, yul_id, **kwargs) self._entrypoint: YulNode = YulNode(entrypoint, self) @@ -333,15 +342,19 @@ class YulBlock(YulScope): # dispatches to a specialized function based on a lookup dictionary. -def convert_yul_block(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_block( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: for statement in ast["statements"]: parent = convert_yul(root, parent, statement, node_scope) return parent -def convert_yul_function_definition(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: +def convert_yul_function_definition( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: func = FunctionContract(root.compilation_unit) - yul_function = YulFunction(func, root, ast) + yul_function = YulFunction(func, root, ast, node_scope) root.contract.add_function(func) root.compilation_unit.add_function(func) @@ -353,7 +366,9 @@ def convert_yul_function_definition(root: YulScope, parent: YulNode, ast: Dict) return parent -def convert_yul_variable_declaration(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_variable_declaration( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: for variable_ast in ast["variables"]: parent = convert_yul(root, parent, variable_ast, node_scope) @@ -364,14 +379,18 @@ def convert_yul_variable_declaration(root: YulScope, parent: YulNode, ast: Dict, return node -def convert_yul_assignment(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_assignment( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: node = root.new_node(NodeType.EXPRESSION, ast["src"]) node.add_unparsed_expression(ast) link_underlying_nodes(parent, node) return node -def convert_yul_expression_statement(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_expression_statement( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: src = ast["src"] expression_ast = ast["expression"] @@ -382,7 +401,9 @@ def convert_yul_expression_statement(root: YulScope, parent: YulNode, ast: Dict, return expression -def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_if( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: # we're cheating and pretending that yul supports if/else so we can convert switch cleaner src = ast["src"] @@ -409,7 +430,9 @@ def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union return end -def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_switch( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: """ This is unfortunate. We don't really want a switch in our IR so we're going to translate it into a series of if/else statements. @@ -493,7 +516,9 @@ def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict, node_scope: U return convert_yul(root, parent, rewritten_switch, node_scope) -def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_for_loop( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: pre_ast = ast["pre"] condition_ast = ast["condition"] post_ast = ast["post"] @@ -521,25 +546,33 @@ def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict, node_scope: return end_loop -def convert_yul_break(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_break( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: break_ = root.new_node(NodeType.BREAK, ast["src"]) link_underlying_nodes(parent, break_) return break_ -def convert_yul_continue(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_continue( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: continue_ = root.new_node(NodeType.CONTINUE, ast["src"]) link_underlying_nodes(parent, continue_) return continue_ -def convert_yul_leave(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_leave( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: leave = root.new_node(NodeType.RETURN, ast["src"]) link_underlying_nodes(parent, leave) return leave -def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_typed_name( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: local_var = LocalVariable() var = YulLocalVariable(local_var, root, ast) @@ -552,13 +585,17 @@ def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict, _node_sco return node -def convert_yul_unsupported(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul_unsupported( + root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope] +) -> YulNode: raise SlitherException( f"no converter available for {ast['nodeType']} {json.dumps(ast, indent=2)}" ) -def convert_yul(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode: +def convert_yul( + root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope] +) -> YulNode: return converters.get(ast["nodeType"], convert_yul_unsupported)(root, parent, ast, node_scope)