Merge pull request #293 from crytic/dev-missing-irs-conversion

Translate to SlithIR missing expressions
pull/298/head
Feist Josselin 5 years ago committed by GitHub
commit f2c8f55da0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      scripts/tests_generate_expected_json_4.sh
  2. 2
      scripts/travis_test_etherscan.sh
  3. 4
      slither/core/cfg/node.py
  4. 224
      slither/core/declarations/function.py
  5. 2
      slither/detectors/variables/possible_const_state_variables.py
  6. 8
      slither/printers/summary/slithir.py
  7. 6
      slither/slithir/convert.py
  8. 9
      slither/slithir/tmp_operations/tmp_call.py
  9. 46
      slither/solc_parsing/declarations/contract.py
  10. 151
      slither/solc_parsing/declarations/function.py
  11. 4
      slither/solc_parsing/slitherSolc.py
  12. 80
      tests/expected_json/deprecated_calls.deprecated-standards.json
  13. 4
      tests/expected_json/deprecated_calls.deprecated-standards.txt
  14. 2
      utils/similarity/encode.py

@ -21,7 +21,7 @@ generate_expected_json(){
} }
#generate_expected_json tests/deprecated_calls.sol "deprecated-standards" generate_expected_json tests/deprecated_calls.sol "deprecated-standards"
#generate_expected_json tests/erc20_indexed.sol "erc20-indexed" #generate_expected_json tests/erc20_indexed.sol "erc20-indexed"
#generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface" #generate_expected_json tests/incorrect_erc20_interface.sol "erc20-interface"
#generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface" #generate_expected_json tests/incorrect_erc721_interface.sol "erc721-interface"

@ -18,7 +18,7 @@ fi
slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --solc "./solc-0.4.25" slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --solc "./solc-0.4.25"
if [ $? -ne 76 ] if [ $? -ne 75 ]
then then
echo "Etherscan test failed" echo "Etherscan test failed"
exit -1 exit -1

@ -62,6 +62,10 @@ class NodeType:
# Only modifier node # Only modifier node
PLACEHOLDER = 0x40 PLACEHOLDER = 0x40
# Node not related to the CFG
# Use for state variable declaration, or modifier calls
STANDALONE = 0x50
# @staticmethod # @staticmethod
def str(t): def str(t):

@ -4,6 +4,7 @@
import logging import logging
from collections import namedtuple from collections import namedtuple
from itertools import groupby from itertools import groupby
from enum import Enum
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance from slither.core.children.child_inheritance import ChildInheritance
@ -13,12 +14,22 @@ from slither.core.declarations.solidity_variables import (SolidityFunction,
from slither.core.expressions import (Identifier, IndexAccess, MemberAccess, from slither.core.expressions import (Identifier, IndexAccess, MemberAccess,
UnaryOperation) UnaryOperation)
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.utils.utils import unroll
logger = logging.getLogger("Function") logger = logging.getLogger("Function")
ReacheableNode = namedtuple('ReacheableNode', ['node', 'ir']) ReacheableNode = namedtuple('ReacheableNode', ['node', 'ir'])
ModifierStatements = namedtuple('Modifier', ['modifier', 'node'])
class FunctionType(Enum):
NORMAL = 0
CONSTRUCTOR = 1
FALLBACK = 2
CONSTRUCTOR_VARIABLES = 3 # Fake function to hold variable declaration statements
class Function(ChildContract, ChildInheritance, SourceMapping): class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
Function class Function class
@ -31,7 +42,7 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
self._pure = None self._pure = None
self._payable = None self._payable = None
self._visibility = None self._visibility = None
self._is_constructor = None
self._is_implemented = None self._is_implemented = None
self._is_empty = None self._is_empty = None
self._entry_point = None self._entry_point = None
@ -91,6 +102,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
self._reachable_from_nodes = set() self._reachable_from_nodes = set()
self._reachable_from_functions = set() self._reachable_from_functions = set()
# Constructor, fallback, State variable constructor
self._function_type = None
self._is_constructor = None
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -103,11 +117,12 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
str: function name str: function name
""" """
if self._name == '': if self._function_type == FunctionType.CONSTRUCTOR:
if self.is_constructor:
return 'constructor' return 'constructor'
else: elif self._function_type == FunctionType.FALLBACK:
return 'fallback' return 'fallback'
elif self._function_type == FunctionType.CONSTRUCTOR_VARIABLES:
return 'slitherConstructorVariables'
return self._name return self._name
@property @property
@ -128,12 +143,6 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
name, parameters, _ = self.signature name, parameters, _ = self.signature
return self.contract_declarer.name + '.' + name + '(' + ','.join(parameters) + ')' return self.contract_declarer.name + '.' + name + '(' + ','.join(parameters) + ')'
@property
def is_constructor(self):
"""
bool: True if the function is the constructor
"""
return self._is_constructor or self._name == self.contract_declarer.name
@property @property
def contains_assembly(self): def contains_assembly(self):
@ -151,6 +160,41 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
return self.contract_declarer == contract return self.contract_declarer == contract
# endregion
###################################################################################
###################################################################################
# region Type (FunctionType)
###################################################################################
###################################################################################
def set_function_type(self, t):
assert isinstance(t, FunctionType)
self._function_type = t
@property
def is_constructor(self):
"""
bool: True if the function is the constructor
"""
return self._function_type == FunctionType.CONSTRUCTOR
@property
def is_constructor_variables(self):
"""
bool: True if the function is the constructor of the variables
Slither has a inbuilt function to hold the state variables initialization
"""
return self._function_type == FunctionType.CONSTRUCTOR_VARIABLES
@property
def is_fallback(self):
"""
Determine if the function is the fallback function for the contract
Returns
(bool)
"""
return self._function_type == FunctionType.FALLBACK
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -179,6 +223,9 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
return self._visibility return self._visibility
def set_visibility(self, v):
self._visibility = v
@property @property
def view(self): def view(self):
""" """
@ -245,6 +292,11 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
return self._entry_point return self._entry_point
def add_node(self, node):
if not self._entry_point:
self._entry_point = node
self._nodes.append(node)
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################
@ -324,6 +376,13 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
""" """
list(Modifier): List of the modifiers list(Modifier): List of the modifiers
""" """
return [c.modifier for c in self._modifiers]
@property
def modifiers_statements(self):
"""
list(ModifierCall): List of the modifiers call (include expression and irs)
"""
return list(self._modifiers) return list(self._modifiers)
@property @property
@ -335,7 +394,16 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
included. included.
""" """
# This is a list of contracts internally, so we convert it to a list of constructor functions. # This is a list of contracts internally, so we convert it to a list of constructor functions.
return [c.constructors_declared for c in self._explicit_base_constructor_calls if c.constructors_declared] return [c.modifier.constructors_declared for c in self._explicit_base_constructor_calls if c.modifier.constructors_declared]
@property
def explicit_base_constructor_calls_statements(self):
"""
list(ModifierCall): List of the base constructors called explicitly by this presumed constructor definition.
"""
# This is a list of contracts internally, so we convert it to a list of constructor functions.
return [c for c in self._explicit_base_constructor_calls if c.modifier.constructors_declared]
# endregion # endregion
@ -986,13 +1054,6 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
args_vars = self.all_solidity_variables_used_as_args() args_vars = self.all_solidity_variables_used_as_args()
return SolidityVariableComposed('msg.sender') in conditional_vars + args_vars return SolidityVariableComposed('msg.sender') in conditional_vars + args_vars
def is_fallback(self):
"""
Determine if the function is the fallback function for the contract
Returns
(bool)
"""
return self._name == "" and not self.is_constructor
# endregion # endregion
################################################################################### ###################################################################################
@ -1100,6 +1161,133 @@ class Function(ChildContract, ChildInheritance, SourceMapping):
# endregion # endregion
###################################################################################
###################################################################################
# region SlithIr and SSA
###################################################################################
###################################################################################
def get_last_ssa_state_variables_instances(self):
from slither.slithir.variables import ReferenceVariable
from slither.slithir.operations import OperationWithLValue
from slither.core.cfg.node import NodeType
if not self.is_implemented:
return dict()
# node, values
to_explore = [(self._entry_point, dict())]
# node -> values
explored = dict()
# name -> instances
ret = dict()
while to_explore:
node, values = to_explore[0]
to_explore = to_explore[1::]
if node.type != NodeType.ENTRYPOINT:
for ir_ssa in node.irs_ssa:
if isinstance(ir_ssa, OperationWithLValue):
lvalue = ir_ssa.lvalue
if isinstance(lvalue, ReferenceVariable):
lvalue = lvalue.points_to_origin
if isinstance(lvalue, StateVariable):
values[lvalue.canonical_name] = {lvalue}
# Check for fixpoint
if node in explored:
if values == explored[node]:
continue
for k, instances in values.items():
if not k in explored[node]:
explored[node][k] = set()
explored[node][k] |= instances
values = explored[node]
else:
explored[node] = values
# Return condition
if not node.sons and node.type != NodeType.THROW:
for name, instances in values.items():
if name not in ret:
ret[name] = set()
ret[name] |= instances
for son in node.sons:
to_explore.append((son, dict(values)))
return ret
@staticmethod
def _unchange_phi(ir):
from slither.slithir.operations import (Phi, PhiCallback)
if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1:
return False
if not ir.rvalues:
return True
return ir.rvalues[0] == ir.lvalue
def fix_phi(self, last_state_variables_instances, initial_state_variables_instances):
from slither.slithir.operations import (InternalCall, PhiCallback)
from slither.slithir.variables import (Constant, StateIRVariable)
for node in self.nodes:
for ir in node.irs_ssa:
if node == self.entry_point:
if isinstance(ir.lvalue, StateIRVariable):
additional = [initial_state_variables_instances[ir.lvalue.canonical_name]]
additional += last_state_variables_instances[ir.lvalue.canonical_name]
ir.rvalues = list(set(additional + ir.rvalues))
# function parameter
else:
# find index of the parameter
idx = self.parameters.index(ir.lvalue.non_ssa_version)
# find non ssa version of that index
additional = [n.ir.arguments[idx] for n in self.reachable_from_nodes]
additional = unroll(additional)
additional = [a for a in additional if not isinstance(a, Constant)]
ir.rvalues = list(set(additional + ir.rvalues))
if isinstance(ir, PhiCallback):
callee_ir = ir.callee_ir
if isinstance(callee_ir, InternalCall):
last_ssa = callee_ir.function.get_last_ssa_state_variables_instances()
if ir.lvalue.canonical_name in last_ssa:
ir.rvalues = list(last_ssa[ir.lvalue.canonical_name])
else:
ir.rvalues = [ir.lvalue]
else:
additional = last_state_variables_instances[ir.lvalue.canonical_name]
ir.rvalues = list(set(additional + ir.rvalues))
node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)]
def generate_slithir_and_analyze(self):
for node in self.nodes:
node.slithir_generation()
for modifier_statement in self.modifiers_statements:
modifier_statement.node.slithir_generation()
for modifier_statement in self.explicit_base_constructor_calls_statements:
modifier_statement.node.slithir_generation()
self._analyze_read_write()
self._analyze_calls()
def generate_slithir_ssa(self, all_ssa_state_variables_instances):
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import (compute_dominance_frontier,
compute_dominators)
compute_dominators(self.nodes)
compute_dominance_frontier(self.nodes)
transform_slithir_vars_to_ssa(self)
add_ssa_ir(self, all_ssa_state_variables_instances)
def update_read_write_using_ssa(self):
for node in self.nodes:
node.update_read_write_using_ssa()
self._analyze_read_write()
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region Built in definitions # region Built in definitions

@ -76,7 +76,7 @@ class ConstCandidateStateVars(AbstractDetector):
all_functions = [c.all_functions_called for c in self.slither.contracts] all_functions = [c.all_functions_called for c in self.slither.contracts]
all_functions = list(set([item for sublist in all_functions for item in sublist])) all_functions = list(set([item for sublist in all_functions for item in sublist]))
all_variables_written = [f.state_variables_written for f in all_functions] all_variables_written = [f.state_variables_written for f in all_functions if not f.is_constructor_variables]
all_variables_written = set([item for sublist in all_variables_written for item in sublist]) all_variables_written = set([item for sublist in all_variables_written for item in sublist])
constable_variables = [v for v in all_non_constant_elementary_variables constable_variables = [v for v in all_non_constant_elementary_variables

@ -34,6 +34,14 @@ class PrinterSlithIR(AbstractPrinter):
print('\t\tIRs:') print('\t\tIRs:')
for ir in node.irs: for ir in node.irs:
print('\t\t\t{}'.format(ir)) print('\t\t\t{}'.format(ir))
for modifier_statement in function.modifiers_statements:
print(f'\t\tModifier Call {modifier_statement.node.expression}')
for ir in modifier_statement.node.irs:
print('\t\t\t{}'.format(ir))
for modifier_statement in function.explicit_base_constructor_calls_statements:
print(f'\t\tConstructor Call {modifier_statement.node.expression}')
for ir in modifier_statement.node.irs:
print('\t\t\t{}'.format(ir))
for modifier in contract.modifiers: for modifier in contract.modifiers:
print('\tModifier {}'.format(modifier.canonical_name)) print('\tModifier {}'.format(modifier.canonical_name))
for node in modifier.nodes: for node in modifier.nodes:

@ -586,6 +586,12 @@ def extract_tmp_call(ins, contract):
if isinstance(ins.called, Event): if isinstance(ins.called, Event):
return EventCall(ins.called.name) return EventCall(ins.called.name)
if isinstance(ins.called, Contract):
internalcall = InternalCall(ins.called.constructor, ins.nbr_arguments, ins.lvalue,
ins.type_call)
internalcall.call_id = ins.call_id
return internalcall
raise Exception('Not extracted {} {}'.format(type(ins.called), ins)) raise Exception('Not extracted {} {}'.format(type(ins.called), ins))

@ -1,14 +1,13 @@
from slither.slithir.operations.lvalue import OperationWithLValue from slither.core.declarations import Event, Contract, SolidityVariableComposed, SolidityFunction, Structure
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.core.declarations.solidity_variables import SolidityVariableComposed, SolidityFunction from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.declarations.structure import Structure
from slither.core.declarations.event import Event
class TmpCall(OperationWithLValue): class TmpCall(OperationWithLValue):
def __init__(self, called, nbr_arguments, result, type_call): def __init__(self, called, nbr_arguments, result, type_call):
assert isinstance(called, (Variable, assert isinstance(called, (Contract,
Variable,
SolidityVariableComposed, SolidityVariableComposed,
SolidityFunction, SolidityFunction,
Structure, Structure,

@ -1,7 +1,10 @@
import logging import logging
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.function import Function, FunctionType
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum
from slither.core.cfg.node import Node, NodeType
from slither.core.expressions import AssignmentOperation, Identifier, AssignmentOperationType
from slither.slithir.variables import StateIRVariable from slither.slithir.variables import StateIRVariable
from slither.solc_parsing.declarations.event import EventSolc from slither.solc_parsing.declarations.event import EventSolc
from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.function import FunctionSolc
@ -319,7 +322,6 @@ class ContractSolc04(Contract):
:return: :return:
""" """
all_elements = {} all_elements = {}
accessible_elements = {}
for father in self.inheritance: for father in self.inheritance:
for element in getter(father): for element in getter(father):
@ -368,6 +370,48 @@ class ContractSolc04(Contract):
pass pass
return return
def _create_node(self, func, counter, variable):
# Function uses to create node for state variable declaration statements
node = Node(NodeType.STANDALONE, counter)
node.set_offset(variable.source_mapping, self.slither)
node.set_function(func)
func.add_node(node)
expression = AssignmentOperation(Identifier(variable),
variable.expression,
AssignmentOperationType.ASSIGN,
variable.type)
node.add_expression(expression)
return node
def add_constructor_variables(self):
if self.state_variables:
found_candidate = False
for (idx, variable_candidate) in enumerate(self.state_variables):
if variable_candidate.expression and not variable_candidate.is_constant:
found_candidate = True
break
if found_candidate:
constructor_variable = Function()
constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
constructor_variable.set_contract(self)
constructor_variable.set_contract_declarer(self)
constructor_variable.set_visibility('internal')
self._functions[constructor_variable.canonical_name] = constructor_variable
prev_node = self._create_node(constructor_variable, 0, variable_candidate)
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.add_son(next_node)
next_node.add_father(prev_node)
counter += 1
def analyze_state_variables(self): def analyze_state_variables(self):
for var in self.variables: for var in self.variables:
var.analyze(self) var.analyze(self)

@ -4,16 +4,10 @@ import logging
from slither.core.cfg.node import NodeType, link_nodes from slither.core.cfg.node import NodeType, link_nodes
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.function import Function from slither.core.declarations.function import Function, ModifierStatements, FunctionType
from slither.core.dominators.utils import (compute_dominance_frontier,
compute_dominators)
from slither.core.expressions import AssignmentOperation from slither.core.expressions import AssignmentOperation
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import (InternalCall, OperationWithLValue, Phi,
PhiCallback)
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.slithir.variables import (Constant, ReferenceVariable,
StateIRVariable)
from slither.solc_parsing.cfg.node import NodeSolc from slither.solc_parsing.cfg.node import NodeSolc
from slither.solc_parsing.expressions.expression_parsing import \ from slither.solc_parsing.expressions.expression_parsing import \
parse_expression parse_expression
@ -23,7 +17,6 @@ from slither.solc_parsing.variables.local_variable_init_from_tuple import \
from slither.solc_parsing.variables.variable_declaration import \ from slither.solc_parsing.variables.variable_declaration import \
MultipleVariablesDeclaration MultipleVariablesDeclaration
from slither.utils.expression_manipulations import SplitTernaryExpression from slither.utils.expression_manipulations import SplitTernaryExpression
from slither.utils.utils import unroll
from slither.visitors.expression.export_values import ExportValues from slither.visitors.expression.export_values import ExportValues
from slither.visitors.expression.has_conditional import HasConditional from slither.visitors.expression.has_conditional import HasConditional
from slither.solc_parsing.exceptions import ParsingError from slither.solc_parsing.exceptions import ParsingError
@ -139,14 +132,20 @@ class FunctionSolc(Function):
if 'constant' in attributes: if 'constant' in attributes:
self._view = attributes['constant'] self._view = attributes['constant']
self._is_constructor = False if self._name == '':
self._function_type = FunctionType.FALLBACK
else:
self._function_type = FunctionType.NORMAL
if self._name == self.contract_declarer.name:
self._function_type = FunctionType.CONSTRUCTOR
if 'isConstructor' in attributes: if 'isConstructor' in attributes and attributes['isConstructor']:
self._is_constructor = attributes['isConstructor'] self._function_type = FunctionType.CONSTRUCTOR
if 'kind' in attributes: if 'kind' in attributes:
if attributes['kind'] == 'constructor': if attributes['kind'] == 'constructor':
self._is_constructor = True self._function_type = FunctionType.CONSTRUCTOR
if 'visibility' in attributes: if 'visibility' in attributes:
self._visibility = attributes['visibility'] self._visibility = attributes['visibility']
@ -220,6 +219,12 @@ class FunctionSolc(Function):
for node in self.nodes: for node in self.nodes:
node.analyze_expressions(self) node.analyze_expressions(self)
for modifier_statement in self.modifiers_statements:
modifier_statement.node.analyze_expressions(self)
for modifier_statement in self.explicit_base_constructor_calls_statements:
modifier_statement.node.analyze_expressions(self)
self._filter_ternary() self._filter_ternary()
self._remove_alone_endif() self._remove_alone_endif()
@ -897,9 +902,15 @@ class FunctionSolc(Function):
self._expression_modifiers.append(m) self._expression_modifiers.append(m)
for m in ExportValues(m).result(): for m in ExportValues(m).result():
if isinstance(m, Function): if isinstance(m, Function):
self._modifiers.append(m) node = self._new_node(NodeType.STANDALONE, modifier['src'])
node.add_unparsed_expression(modifier)
self._modifiers.append(ModifierStatements(modifier=m,
node=node))
elif isinstance(m, Contract): elif isinstance(m, Contract):
self._explicit_base_constructor_calls.append(m) node = self._new_node(NodeType.STANDALONE, modifier['src'])
node.add_unparsed_expression(modifier)
self._explicit_base_constructor_calls.append(ModifierStatements(modifier=m,
node=node))
# endregion # endregion
################################################################################### ###################################################################################
@ -1026,113 +1037,5 @@ class FunctionSolc(Function):
# endregion # endregion
###################################################################################
###################################################################################
# region SlithIr and SSA
###################################################################################
###################################################################################
def get_last_ssa_state_variables_instances(self):
if not self.is_implemented:
return dict()
# node, values
to_explore = [(self._entry_point, dict())]
# node -> values
explored = dict()
# name -> instances
ret = dict()
while to_explore:
node, values = to_explore[0]
to_explore = to_explore[1::]
if node.type != NodeType.ENTRYPOINT:
for ir_ssa in node.irs_ssa:
if isinstance(ir_ssa, OperationWithLValue):
lvalue = ir_ssa.lvalue
if isinstance(lvalue, ReferenceVariable):
lvalue = lvalue.points_to_origin
if isinstance(lvalue, StateVariable):
values[lvalue.canonical_name] = {lvalue}
# Check for fixpoint
if node in explored:
if values == explored[node]:
continue
for k, instances in values.items():
if not k in explored[node]:
explored[node][k] = set()
explored[node][k] |= instances
values = explored[node]
else:
explored[node] = values
# Return condition
if not node.sons and node.type != NodeType.THROW:
for name, instances in values.items():
if name not in ret:
ret[name] = set()
ret[name] |= instances
for son in node.sons:
to_explore.append((son, dict(values)))
return ret
@staticmethod
def _unchange_phi(ir):
if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1:
return False
if not ir.rvalues:
return True
return ir.rvalues[0] == ir.lvalue
def fix_phi(self, last_state_variables_instances, initial_state_variables_instances):
for node in self.nodes:
for ir in node.irs_ssa:
if node == self.entry_point:
if isinstance(ir.lvalue, StateIRVariable):
additional = [initial_state_variables_instances[ir.lvalue.canonical_name]]
additional += last_state_variables_instances[ir.lvalue.canonical_name]
ir.rvalues = list(set(additional + ir.rvalues))
# function parameter
else:
# find index of the parameter
idx = self.parameters.index(ir.lvalue.non_ssa_version)
# find non ssa version of that index
additional = [n.ir.arguments[idx] for n in self.reachable_from_nodes]
additional = unroll(additional)
additional = [a for a in additional if not isinstance(a, Constant)]
ir.rvalues = list(set(additional + ir.rvalues))
if isinstance(ir, PhiCallback):
callee_ir = ir.callee_ir
if isinstance(callee_ir, InternalCall):
last_ssa = callee_ir.function.get_last_ssa_state_variables_instances()
if ir.lvalue.canonical_name in last_ssa:
ir.rvalues = list(last_ssa[ir.lvalue.canonical_name])
else:
ir.rvalues = [ir.lvalue]
else:
additional = last_state_variables_instances[ir.lvalue.canonical_name]
ir.rvalues = list(set(additional + ir.rvalues))
node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)]
def generate_slithir_and_analyze(self):
for node in self.nodes:
node.slithir_generation()
self._analyze_read_write()
self._analyze_calls()
def generate_slithir_ssa(self, all_ssa_state_variables_instances):
compute_dominators(self.nodes)
compute_dominance_frontier(self.nodes)
transform_slithir_vars_to_ssa(self)
add_ssa_ir(self, all_ssa_state_variables_instances)
def update_read_write_using_ssa(self):
for node in self.nodes:
node.update_read_write_using_ssa()
self._analyze_read_write()

@ -373,10 +373,14 @@ class SlitherSolc(Slither):
contract.analyze_content_modifiers() contract.analyze_content_modifiers()
contract.analyze_content_functions() contract.analyze_content_functions()
contract.set_is_analyzed(True) contract.set_is_analyzed(True)
def _convert_to_slithir(self): def _convert_to_slithir(self):
for contract in self.contracts: for contract in self.contracts:
contract.add_constructor_variables()
contract.convert_expression_to_slithir() contract.convert_expression_to_slithir()
self._propagate_function_calls() self._propagate_function_calls()
for contract in self.contracts: for contract in self.contracts:

@ -692,6 +692,86 @@
} }
} }
] ]
},
{
"check": "deprecated-standards",
"impact": "Informational",
"confidence": "High",
"description": "Deprecated standard detected @ tests/deprecated_calls.sol#2:\n\t- Usage of \"block.blockhash()\" should be replaced with \"blockhash()\"\n",
"elements": [
{
"type": "node",
"name": "globalBlockHash = block.blockhash(0)",
"source_mapping": {
"start": 48,
"length": 44,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"is_dependency": false,
"lines": [
2
],
"starting_column": 5,
"ending_column": 49
},
"type_specific_fields": {
"parent": {
"type": "function",
"name": "slitherConstructorVariables",
"source_mapping": null,
"type_specific_fields": {
"parent": {
"type": "contract",
"name": "ContractWithDeprecatedReferences",
"source_mapping": {
"start": 0,
"length": 906,
"filename_used": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_relative": "tests/deprecated_calls.sol",
"filename_absolute": "/home/travis/build/crytic/slither/tests/deprecated_calls.sol",
"filename_short": "tests/deprecated_calls.sol",
"is_dependency": false,
"lines": [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27
],
"starting_column": 1,
"ending_column": null
}
},
"signature": "slitherConstructorVariables()"
}
}
}
}
]
} }
] ]
} }

@ -13,5 +13,7 @@ Deprecated standard detected @ tests/deprecated_calls.sol#22:
- Usage of "callcode" should be replaced with "delegatecall" - Usage of "callcode" should be replaced with "delegatecall"
Deprecated standard detected @ tests/deprecated_calls.sol#25: Deprecated standard detected @ tests/deprecated_calls.sol#25:
- Usage of "suicide()" should be replaced with "selfdestruct()" - Usage of "suicide()" should be replaced with "selfdestruct()"
Deprecated standard detected @ tests/deprecated_calls.sol#2:
- Usage of "block.blockhash()" should be replaced with "blockhash()"
Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards Reference: https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards
INFO:Slither:tests/deprecated_calls.sol analyzed (1 contracts), 7 result(s) found INFO:Slither:tests/deprecated_calls.sol analyzed (1 contracts), 8 result(s) found

@ -195,7 +195,7 @@ def encode_contract(cfilename, **kwargs):
# Iterate over all the functions # Iterate over all the functions
for function in contract.functions_declared: for function in contract.functions_declared:
if function.nodes == []: if function.nodes == [] or function.is_constructor_variables:
continue continue
x = (cfilename,contract.name,function.name) x = (cfilename,contract.name,function.name)

Loading…
Cancel
Save