diff --git a/slither/core/cfg/node.py b/slither/core/cfg/node.py index b9077f976..8019b77e7 100644 --- a/slither/core/cfg/node.py +++ b/slither/core/cfg/node.py @@ -9,6 +9,7 @@ from slither.core.declarations.solidity_variables import (SolidityFunction, SolidityVariable) from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.state_variable import StateVariable +from slither.core.variables.local_variable import LocalVariable from slither.core.variables.variable import Variable from slither.slithir.convert import convert_expression from slither.slithir.operations import (Balance, HighLevelCall, Index, @@ -137,6 +138,9 @@ class Node(SourceMapping, ChildFunction): self._state_vars_read = [] self._solidity_vars_read = [] + self._local_vars_read = [] + self._local_vars_written = [] + self._expression_vars_written = [] self._expression_vars_read = [] self._expression_calls = [] @@ -221,6 +225,13 @@ class Node(SourceMapping, ChildFunction): """ return list(self._state_vars_read) + @property + def local_variables_read(self): + """ + list(LocalVariable): Local variables read + """ + return list(self._local_vars_read) + @property def solidity_variables_read(self): """ @@ -246,6 +257,13 @@ class Node(SourceMapping, ChildFunction): """ return list(self._state_vars_written) + @property + def local_variables_written(self): + """ + list(LocalVariable): Local variables written + """ + return list(self._local_vars_written) + @property def variables_written_as_expression(self): return self._expression_vars_written @@ -311,6 +329,7 @@ class Node(SourceMapping, ChildFunction): self._variable_declaration = var if var.expression: self._vars_written += [var] + self._local_vars_written += [var] @property def variable_declaration(self): @@ -489,9 +508,11 @@ class Node(SourceMapping, ChildFunction): self._vars_read = list(set(self._vars_read)) self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)] + self._local_vars_read = [v for v in self._vars_read if isinstance(v, LocalVariable)] self._solidity_vars_read = [v for v in self._vars_read if isinstance(v, SolidityVariable)] self._vars_written = list(set(self._vars_written)) self._state_vars_written = [v for v in self._vars_written if isinstance(v, StateVariable)] + self._local_vars_written = [v for v in self._vars_written if isinstance(v, LocalVariable)] self._internal_calls = list(set(self._internal_calls)) self._solidity_calls = list(set(self._solidity_calls)) self._high_level_calls = list(set(self._high_level_calls)) diff --git a/slither/slithir/utils/ssa.py b/slither/slithir/utils/ssa.py index 85cc04602..258e29d7f 100644 --- a/slither/slithir/utils/ssa.py +++ b/slither/slithir/utils/ssa.py @@ -59,12 +59,14 @@ def add_ssa_ir(function): for variable_name, nodes in node.phi_origins.items(): if len(nodes)<2 : continue + if not is_used_later(node, variable_name, []): + continue # assumption: at this level we can retrieve # an instance of the variable # by looking at the variables written # of any of the nodes for n in nodes: - variable = next((v for v in n.variables_written if v.name == variable_name), None) + variable = next((v for v in n.local_variables_written if v.name == variable_name), None) if variable is None: variable = n.variable_declaration if variable: @@ -135,6 +137,25 @@ def update_lvalue(new_ir, node, local_variables_instances, global_variables_inst to_update = to_update.points_to to_update.points_to = new_var +def is_used_later(node, variable_name, visited): + # TODO: does not handle the case where its read and written in the declaration node + # It can be problematic if this happens in a loop/if structure + # Ex: + # for(;true;){ + # if(true){ + # uint a = a; + # } + # .. + if node in visited: + return False + # shared visited + visited.append(node) + if any(v.name == variable_name for v in node.local_variables_read): + return True + if any(v.name == variable_name for v in node.local_variables_written): + return False + return any(is_used_later(son, variable_name, visited) for son in node.sons) + def generate_ssa_irs(node, local_variables_instances, global_variables_instances): if node.variable_declaration: @@ -161,7 +182,7 @@ def add_phi_origins(node, variables_definition): # Add new key to variables_definition # the key is the variable_name and the value the node where its written variables_definition = dict(variables_definition, - **{v.name: node for v in node.variables_written}) + **{v.name: node for v in node.local_variables_written}) # For unini variable declaration if node.variable_declaration and\