Use cache system for function.all_* properties

pull/162/head
Josselin 6 years ago
parent 1cdc34ec77
commit 00c38a0945
  1. 134
      slither/core/declarations/function.py

@ -60,6 +60,21 @@ class Function(ChildContract, SourceMapping):
self._payable = False self._payable = False
self._contains_assembly = False self._contains_assembly = False
self._expressions = None
self._slithir_operations = None
self._all_expressions = None
self._all_slithir_operations = None
self._all_internals_calls = None
self._all_high_level_calls = None
self._all_low_level_calls = None
self._all_state_variables_read = None
self._all_solidity_variables_read = None
self._all_state_variables_written = None
self._all_conditional_state_variables_read = None
self._all_conditional_solidity_variables_read = None
self._all_solidity_variables_used_as_args = None
@property @property
def contains_assembly(self): def contains_assembly(self):
return self._contains_assembly return self._contains_assembly
@ -340,9 +355,22 @@ class Function(ChildContract, SourceMapping):
""" """
list(Expression): List of the expressions list(Expression): List of the expressions
""" """
if self._expressions is None:
expressions = [n.expression for n in self.nodes] expressions = [n.expression for n in self.nodes]
expressions = [e for e in expressions if e] expressions = [e for e in expressions if e]
return expressions self._expressions = expressions
return self._expressions
@property
def slithir_operations(self):
"""
list(Operation): List of the slithir operations
"""
if self._slithir_operations is None:
operations = [n.irs for n in self.nodes]
operations = [item for sublist in operations for item in sublist if item]
self._slithir_operations = operations
return self._slithir_operations
@property @property
def signature(self): def signature(self):
@ -518,78 +546,134 @@ class Function(ChildContract, SourceMapping):
def all_state_variables_read(self): def all_state_variables_read(self):
""" recursive version of variables_read """ recursive version of variables_read
""" """
return self._explore_functions(lambda x: x.state_variables_read) if self._all_state_variables_read is None:
self._all_state_variables_read = self._explore_functions(
lambda x: x.state_variables_read)
return self._all_state_variables_read
def all_solidity_variables_read(self): def all_solidity_variables_read(self):
""" recursive version of solidity_read """ recursive version of solidity_read
""" """
return self._explore_functions(lambda x: x.solidity_variables_read) if self._all_solidity_variables_read is None:
self._all_solidity_variables_read = self._explore_functions(
lambda x: x.solidity_variables_read)
return self._all_solidity_variables_read
def all_expressions(self): def all_expressions(self):
""" recursive version of variables_read """ recursive version of variables_read
""" """
return self._explore_functions(lambda x: x.expressions) if self._all_expressions is None:
self._all_expressions = self._explore_functions(lambda x: x.expressions)
return self._all_expressions
def all_slithir_operations(self):
"""
"""
if self._all_slithir_operations is None:
self._all_slithir_operations = self._explore_functions(lambda x: x.slithir_operations)
return self._all_slithir_operations
def all_state_variables_written(self): def all_state_variables_written(self):
""" recursive version of variables_written """ recursive version of variables_written
""" """
return self._explore_functions(lambda x: x.state_variables_written) if self._all_state_variables_written is None:
self._all_state_variables_written = self._explore_functions(
lambda x: x.state_variables_written)
return self._all_state_variables_written
def all_internal_calls(self): def all_internal_calls(self):
""" recursive version of internal_calls """ recursive version of internal_calls
""" """
return self._explore_functions(lambda x: x.internal_calls) if self._all_internals_calls is None:
self._all_internals_calls = self._explore_functions(lambda x: x.internal_calls)
return self._all_internals_calls
def all_conditional_state_variables_read(self, include_loop=True): def all_low_level_calls(self):
""" recursive version of low_level calls
""" """
Return the state variable used in a condition if self._all_low_level_calls is None:
self._all_low_level_calls = self._explore_functions(lambda x: x.low_level_calls)
return self._all_low_level_calls
Over approximate and also return index access def all_high_level_calls(self):
It won't work if the variable is assigned to a temp variable """ recursive version of high_level calls
""" """
def _explore_func(func): if self._all_high_level_calls is None:
self._all_high_level_calls = self._explore_functions(lambda x: x.high_level_calls)
return self._all_high_level_calls
@staticmethod
def _explore_func_cond_read(func, include_loop):
ret = [n.state_variables_read for n in func.nodes if n.is_conditional(include_loop)] ret = [n.state_variables_read for n in func.nodes if n.is_conditional(include_loop)]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
return self._explore_functions(lambda x: _explore_func(x))
def all_conditional_solidity_variables_read(self, include_loop=True): def all_conditional_state_variables_read(self, include_loop=True):
""" """
Return the Soldiity variables directly used in a condtion Return the state variable used in a condition
Use of the IR to filter index access Over approximate and also return index access
Assumption: the solidity vars are used directly in the conditional node
It won't work if the variable is assigned to a temp variable It won't work if the variable is assigned to a temp variable
""" """
if self._all_conditional_state_variables_read is None:
self._all_conditional_state_variables_read = self._explore_functions(
lambda x: self._explore_func_cond_read(x,
include_loop))
return self._all_conditional_state_variables_read
@staticmethod
def _solidity_variable_in_binary(node):
from slither.slithir.operations.binary import Binary from slither.slithir.operations.binary import Binary
def _solidity_variable_in_node(node):
ret = [] ret = []
for ir in node.irs: for ir in node.irs:
if isinstance(ir, Binary): if isinstance(ir, Binary):
ret += ir.read ret += ir.read
return [var for var in ret if isinstance(var, SolidityVariable)] return [var for var in ret if isinstance(var, SolidityVariable)]
def _explore_func(func, f):
@staticmethod
def _explore_func_conditional(func, f, include_loop):
ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)] ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
return self._explore_functions(lambda x: _explore_func(x, _solidity_variable_in_node))
def all_solidity_variables_used_as_args(self): def all_conditional_solidity_variables_read(self, include_loop=True):
""" """
Return the Soldiity variables directly used in a call Return the Soldiity variables directly used in a condtion
Use of the IR to filter index access Use of the IR to filter index access
Used to catch check(msg.sender) Assumption: the solidity vars are used directly in the conditional node
It won't work if the variable is assigned to a temp variable
""" """
if self._all_conditional_solidity_variables_read is None:
self._all_conditional_solidity_variables_read = self._explore_functions(
lambda x: self._explore_func_conditional(x,
self._solidity_variable_in_binary,
include_loop))
return self._all_conditional_solidity_variables_read
@staticmethod
def _solidity_variable_in_internal_calls(node):
from slither.slithir.operations.internal_call import InternalCall from slither.slithir.operations.internal_call import InternalCall
def _solidity_variable_in_node(node):
ret = [] ret = []
for ir in node.irs: for ir in node.irs:
if isinstance(ir, InternalCall): if isinstance(ir, InternalCall):
ret += ir.read ret += ir.read
return [var for var in ret if isinstance(var, SolidityVariable)] return [var for var in ret if isinstance(var, SolidityVariable)]
def _explore_func(func, f):
@staticmethod
def _explore_func_nodes(func, f):
ret = [f(n) for n in func.nodes] ret = [f(n) for n in func.nodes]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
return self._explore_functions(lambda x: _explore_func(x, _solidity_variable_in_node))
def all_solidity_variables_used_as_args(self):
"""
Return the Soldiity variables directly used in a call
Use of the IR to filter index access
Used to catch check(msg.sender)
"""
if self._all_solidity_variables_used_as_args is None:
self._all_solidity_variables_used_as_args = self._explore_functions(
lambda x: self._explore_func_nodes(x, self._solidity_variable_in_internal_calls))
return self._all_solidity_variables_used_as_args
def is_reading(self, variable): def is_reading(self, variable):
""" """

Loading…
Cancel
Save