|
|
@ -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): |
|
|
|
""" |
|
|
|
""" |
|
|
|