Add node.local_variables_written/local_variables_read

Look ahead to add Phi operation only if the variable is used in sons
pull/87/head
Josselin 6 years ago
parent cb6ecbf2bb
commit e25be40be4
  1. 21
      slither/core/cfg/node.py
  2. 25
      slither/slithir/utils/ssa.py

@ -9,6 +9,7 @@ from slither.core.declarations.solidity_variables import (SolidityFunction,
SolidityVariable) SolidityVariable)
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.state_variable import StateVariable 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.core.variables.variable import Variable
from slither.slithir.convert import convert_expression from slither.slithir.convert import convert_expression
from slither.slithir.operations import (Balance, HighLevelCall, Index, from slither.slithir.operations import (Balance, HighLevelCall, Index,
@ -137,6 +138,9 @@ class Node(SourceMapping, ChildFunction):
self._state_vars_read = [] self._state_vars_read = []
self._solidity_vars_read = [] self._solidity_vars_read = []
self._local_vars_read = []
self._local_vars_written = []
self._expression_vars_written = [] self._expression_vars_written = []
self._expression_vars_read = [] self._expression_vars_read = []
self._expression_calls = [] self._expression_calls = []
@ -221,6 +225,13 @@ class Node(SourceMapping, ChildFunction):
""" """
return list(self._state_vars_read) return list(self._state_vars_read)
@property
def local_variables_read(self):
"""
list(LocalVariable): Local variables read
"""
return list(self._local_vars_read)
@property @property
def solidity_variables_read(self): def solidity_variables_read(self):
""" """
@ -246,6 +257,13 @@ class Node(SourceMapping, ChildFunction):
""" """
return list(self._state_vars_written) return list(self._state_vars_written)
@property
def local_variables_written(self):
"""
list(LocalVariable): Local variables written
"""
return list(self._local_vars_written)
@property @property
def variables_written_as_expression(self): def variables_written_as_expression(self):
return self._expression_vars_written return self._expression_vars_written
@ -311,6 +329,7 @@ class Node(SourceMapping, ChildFunction):
self._variable_declaration = var self._variable_declaration = var
if var.expression: if var.expression:
self._vars_written += [var] self._vars_written += [var]
self._local_vars_written += [var]
@property @property
def variable_declaration(self): def variable_declaration(self):
@ -489,9 +508,11 @@ class Node(SourceMapping, ChildFunction):
self._vars_read = list(set(self._vars_read)) self._vars_read = list(set(self._vars_read))
self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)] 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._solidity_vars_read = [v for v in self._vars_read if isinstance(v, SolidityVariable)]
self._vars_written = list(set(self._vars_written)) self._vars_written = list(set(self._vars_written))
self._state_vars_written = [v for v in self._vars_written if isinstance(v, StateVariable)] 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._internal_calls = list(set(self._internal_calls))
self._solidity_calls = list(set(self._solidity_calls)) self._solidity_calls = list(set(self._solidity_calls))
self._high_level_calls = list(set(self._high_level_calls)) self._high_level_calls = list(set(self._high_level_calls))

@ -59,12 +59,14 @@ def add_ssa_ir(function):
for variable_name, nodes in node.phi_origins.items(): for variable_name, nodes in node.phi_origins.items():
if len(nodes)<2 : if len(nodes)<2 :
continue continue
if not is_used_later(node, variable_name, []):
continue
# assumption: at this level we can retrieve # assumption: at this level we can retrieve
# an instance of the variable # an instance of the variable
# by looking at the variables written # by looking at the variables written
# of any of the nodes # of any of the nodes
for n in 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: if variable is None:
variable = n.variable_declaration variable = n.variable_declaration
if variable: 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 = to_update.points_to
to_update.points_to = new_var 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): def generate_ssa_irs(node, local_variables_instances, global_variables_instances):
if node.variable_declaration: if node.variable_declaration:
@ -161,7 +182,7 @@ def add_phi_origins(node, variables_definition):
# Add new key to variables_definition # Add new key to variables_definition
# the key is the variable_name and the value the node where its written # the key is the variable_name and the value the node where its written
variables_definition = dict(variables_definition, 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 # For unini variable declaration
if node.variable_declaration and\ if node.variable_declaration and\

Loading…
Cancel
Save