From cd09f6c64ef221bef1da77a3d4a5ab98eb130e08 Mon Sep 17 00:00:00 2001 From: David Pokora Date: Mon, 4 Feb 2019 18:16:01 -0500 Subject: [PATCH 1/8] Fix UserDefinedTypeName parsing in type_parsing.py to use the 'type' attribute instead of 'name' attribute. --- slither/solc_parsing/solidity_types/type_parsing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index 1a26612dd..ed97e486a 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -160,7 +160,7 @@ def parse_type(t, caller_context): elif t[key] == 'UserDefinedTypeName': if is_compact_ast: return _find_from_type_name(t['typeDescriptions']['typeString'], contract, contracts, structures, enums) - return _find_from_type_name(t['attributes'][key], contract, contracts, structures, enums) + return _find_from_type_name(t['attributes']['type'], contract, contracts, structures, enums) elif t[key] == 'ArrayTypeName': length = None From e8e112c89b57b1d103d6c4e498cd544be9f277c9 Mon Sep 17 00:00:00 2001 From: David Pokora Date: Fri, 8 Feb 2019 10:08:38 -0500 Subject: [PATCH 2/8] Fixed an issue where 'type' node would not exist on old solc in legacy-ast. --- slither/solc_parsing/solidity_types/type_parsing.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index ed97e486a..2b5057dda 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -160,7 +160,10 @@ def parse_type(t, caller_context): elif t[key] == 'UserDefinedTypeName': if is_compact_ast: return _find_from_type_name(t['typeDescriptions']['typeString'], contract, contracts, structures, enums) - return _find_from_type_name(t['attributes']['type'], contract, contracts, structures, enums) + + # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). + type_name_key = 'type' if 'type' in t['attributes'] else key + return _find_from_type_name(t['attributes'][type_name_key], contract, contracts, structures, enums) elif t[key] == 'ArrayTypeName': length = None From fe6789bdc575cb57c38289db6b5f121d61e15cb5 Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 11 Feb 2019 13:53:40 -0500 Subject: [PATCH 3/8] Fixed: - node.high_level_call: support call to this Changed: - use 'contracts.dot' as default name for printers exporting a dot file --- slither/core/cfg/node.py | 2 ++ slither/printers/call/call_graph.py | 3 +++ slither/printers/inheritance/inheritance_graph.py | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/slither/core/cfg/node.py b/slither/core/cfg/node.py index 7b15937e7..855871684 100644 --- a/slither/core/cfg/node.py +++ b/slither/core/cfg/node.py @@ -685,6 +685,8 @@ class Node(SourceMapping, ChildFunction): elif isinstance(ir, (HighLevelCall)) and not isinstance(ir, LibraryCall): if isinstance(ir.destination.type, Contract): self._high_level_calls.append((ir.destination.type, ir.function)) + elif ir.destination == SolidityVariable('this'): + self._high_level_calls.append((self.function.contract, ir.function)) else: self._high_level_calls.append((ir.destination.type.type, ir.function)) elif isinstance(ir, LibraryCall): diff --git a/slither/printers/call/call_graph.py b/slither/printers/call/call_graph.py index a68b7de49..ed5efdfae 100644 --- a/slither/printers/call/call_graph.py +++ b/slither/printers/call/call_graph.py @@ -142,6 +142,9 @@ class PrinterCallGraph(AbstractPrinter): Args: filename(string) """ + if not filename: + filename = "contracts.dot" + if not filename.endswith('.dot'): filename += '.dot' diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index 9897db4b2..468969002 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -171,7 +171,7 @@ class PrinterInheritanceGraph(AbstractPrinter): filename(string) """ if filename == '': - filename = 'export' + filename = 'contracts.dot' if not filename.endswith('.dot'): filename += ".dot" info = 'Inheritance Graph: ' + filename From f468cda4c13e52cb9820f56e757b3b9827e93c4c Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 12 Feb 2019 05:33:52 -0500 Subject: [PATCH 4/8] Change: - node.is_conditional: consider return bool as a conditional node --- slither/core/cfg/node.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/slither/core/cfg/node.py b/slither/core/cfg/node.py index 855871684..d4c70840e 100644 --- a/slither/core/cfg/node.py +++ b/slither/core/cfg/node.py @@ -10,12 +10,13 @@ from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.local_variable import LocalVariable from slither.core.variables.state_variable import StateVariable from slither.core.variables.variable import Variable +from slither.core.solidity_types import ElementaryType from slither.slithir.convert import convert_expression from slither.slithir.operations import (Balance, HighLevelCall, Index, InternalCall, Length, LibraryCall, LowLevelCall, Member, OperationWithLValue, Phi, PhiCallback, - SolidityCall) + SolidityCall, Return) from slither.slithir.variables import (Constant, LocalIRVariable, ReferenceVariable, StateIRVariable, TemporaryVariable, TupleVariable) @@ -424,11 +425,21 @@ class Node(SourceMapping, ChildFunction): def is_conditional(self, include_loop=True): """ Check if the node is a conditional node - A conditional node is either a IF or a require/assert + A conditional node is either a IF or a require/assert or a RETURN bool Returns: bool: True if the node is a conditional node """ - return self.contains_if(include_loop) or self.contains_require_or_assert() + if self.contains_if(include_loop) or self.contains_require_or_assert(): + return True + if self.irs: + last_ir = self.irs[-1] + if last_ir: + if isinstance(last_ir, Return): + for r in last_ir.read: + if r.type == ElementaryType('bool'): + return True + return False + # endregion From c0f9f09b59316c01e00820b8f93e752c2e5f6fc9 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 12 Feb 2019 12:25:54 +0000 Subject: [PATCH 5/8] Fix missing support for this.variable() in reentrancy detector --- slither/detectors/reentrancy/reentrancy.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/slither/detectors/reentrancy/reentrancy.py b/slither/detectors/reentrancy/reentrancy.py index 74dbab7b6..ace071469 100644 --- a/slither/detectors/reentrancy/reentrancy.py +++ b/slither/detectors/reentrancy/reentrancy.py @@ -59,6 +59,8 @@ class Reentrancy(AbstractDetector): # We can check that the function called is # reentrancy-safe if ir.destination == SolidityVariable('this'): + if isinstance(ir.function, Variable): + continue if not ir.function.all_high_level_calls(): if not ir.function.all_low_level_calls(): continue From ece8e324ce3cbc012eb50d74df43d88784a141a9 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 12 Feb 2019 15:48:18 +0000 Subject: [PATCH 6/8] Improve truffle auto version parsing --- slither/__main__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/slither/__main__.py b/slither/__main__.py index 34b11953e..2995c3ddb 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -78,7 +78,10 @@ def process_truffle(dirname, args, detector_classes, printer_classes): package = json.load(f) if 'devDependencies' in package: if 'truffle' in package['devDependencies']: - truffle_version = 'truffle@{}'.format(package['devDependencies']['truffle']) + version = package['devDependencies']['truffle'] + if version.startswith('^'): + version = version[1:] + truffle_version = 'truffle@{}'.format(version) cmd = ['npx', truffle_version,'compile'] logger.info("'{}' running (use --truffle-version truffle@x.x.x to use specific version)".format(' '.join(cmd))) process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) From 821d385f33a3a902392a93ccc1ab908e6689cb2f Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 12 Feb 2019 17:21:15 +0000 Subject: [PATCH 7/8] Improve SSA code readability + add support for tuple ssa conversion --- .../data_dependency/data_dependency.py | 17 +- slither/slithir/utils/ssa.py | 263 ++++++++++-------- slither/slithir/variables/__init__.py | 3 + slither/slithir/variables/tuple.py | 14 +- slither/slithir/variables/tuple_ssa.py | 20 ++ .../visitors/slithir/expression_to_slithir.py | 4 +- 6 files changed, 186 insertions(+), 135 deletions(-) create mode 100644 slither/slithir/variables/tuple_ssa.py diff --git a/slither/analyses/data_dependency/data_dependency.py b/slither/analyses/data_dependency/data_dependency.py index 95cd10754..94e3e534a 100644 --- a/slither/analyses/data_dependency/data_dependency.py +++ b/slither/analyses/data_dependency/data_dependency.py @@ -1,13 +1,14 @@ """ Compute the data depenency between all the SSA variables """ -from slither.core.declarations import Contract, Function -from slither.core.declarations.solidity_variables import \ - SolidityVariableComposed +from slither.core.declarations import (Contract, Enum, Function, + SolidityFunction, SolidityVariable, + SolidityVariableComposed, Structure) from slither.slithir.operations import Index, OperationWithLValue from slither.slithir.variables import (Constant, LocalIRVariable, - ReferenceVariable, StateIRVariable, - TemporaryVariable) + ReferenceVariable, ReferenceVariableSSA, + StateIRVariable, TemporaryVariable, + TemporaryVariableSSA, TupleVariableSSA) ################################################################################### ################################################################################### @@ -243,7 +244,6 @@ def compute_dependency_function(function): function.context[KEY_SSA_UNPROTECTED] = dict() is_protected = function.is_protected() - for node in function.nodes: for ir in node.irs_ssa: if isinstance(ir, OperationWithLValue) and ir.lvalue: @@ -259,10 +259,9 @@ def compute_dependency_function(function): function.context[KEY_NON_SSA_UNPROTECTED] = convert_to_non_ssa(function.context[KEY_SSA_UNPROTECTED]) def convert_variable_to_non_ssa(v): - if isinstance(v, (LocalIRVariable, StateIRVariable)): + if isinstance(v, (LocalIRVariable, StateIRVariable, TemporaryVariableSSA, ReferenceVariableSSA, TupleVariableSSA)): return v.non_ssa_version - if isinstance(v, (TemporaryVariable, ReferenceVariable)): - return next((variable for variable in v.function.slithir_variables if variable.name == v.name)) + assert isinstance(v, (Constant, SolidityVariable, Contract, Enum, SolidityFunction, Structure, Function)) return v def convert_to_non_ssa(data_depencies): diff --git a/slither/slithir/utils/ssa.py b/slither/slithir/utils/ssa.py index 3b16555bb..d2e983616 100644 --- a/slither/slithir/utils/ssa.py +++ b/slither/slithir/utils/ssa.py @@ -1,6 +1,9 @@ import logging from slither.core.cfg.node import NodeType +from slither.core.declarations import (Contract, Enum, Function, + SolidityFunction, SolidityVariable, + SolidityVariableComposed, Structure) from slither.core.variables.local_variable import LocalVariable from slither.core.variables.state_variable import StateVariable from slither.slithir.operations import (Assignment, Balance, Binary, Condition, @@ -14,9 +17,10 @@ from slither.slithir.operations import (Assignment, Balance, Binary, Condition, Push, Return, Send, SolidityCall, Transfer, TypeConversion, Unary, Unpack) -from slither.slithir.variables import (LocalIRVariable, ReferenceVariable, +from slither.slithir.variables import (Constant, LocalIRVariable, + ReferenceVariable, ReferenceVariableSSA, StateIRVariable, TemporaryVariable, - TupleVariable) + TemporaryVariableSSA, TupleVariable, TupleVariableSSA) logger = logging.getLogger('SSA_Conversion') @@ -164,6 +168,7 @@ def generate_ssa_irs(node, local_variables_instances, all_local_variables_instan # They dont need phi function temporary_variables_instances = dict() reference_variables_instances = dict() + tuple_variables_instances = dict() for ir in node.irs: new_ir = copy_ir(ir, @@ -171,6 +176,7 @@ def generate_ssa_irs(node, local_variables_instances, all_local_variables_instan state_variables_instances, temporary_variables_instances, reference_variables_instances, + tuple_variables_instances, all_local_variables_instances) update_lvalue(new_ir, @@ -416,7 +422,81 @@ def add_phi_origins(node, local_variables_definition, state_variables_definition ################################################################################### ################################################################################### -def copy_ir(ir, local_variables_instances, state_variables_instances, temporary_variables_instances, reference_variables_instances, all_local_variables_instances): +def get(variable, local_variables_instances, state_variables_instances, temporary_variables_instances, reference_variables_instances, tuple_variables_instances, all_local_variables_instances): + # variable can be None + # for example, on LowLevelCall, ir.lvalue can be none + if variable is None: + return None + if isinstance(variable, LocalVariable): + if variable.name in local_variables_instances: + return local_variables_instances[variable.name] + new_var = LocalIRVariable(variable) + local_variables_instances[variable.name] = new_var + all_local_variables_instances[variable.name] = new_var + return new_var + if isinstance(variable, StateVariable) and variable.canonical_name in state_variables_instances: + return state_variables_instances[variable.canonical_name] + elif isinstance(variable, ReferenceVariable): + if not variable.index in reference_variables_instances: + new_variable = ReferenceVariableSSA(variable) + if variable.points_to: + new_variable.points_to = get(variable.points_to, + local_variables_instances, + state_variables_instances, + temporary_variables_instances, + reference_variables_instances, + tuple_variables_instances, + all_local_variables_instances) + new_variable.set_type(variable.type) + reference_variables_instances[variable.index] = new_variable + return reference_variables_instances[variable.index] + elif isinstance(variable, TemporaryVariable): + if not variable.index in temporary_variables_instances: + new_variable = TemporaryVariableSSA(variable) + new_variable.set_type(variable.type) + temporary_variables_instances[variable.index] = new_variable + return temporary_variables_instances[variable.index] + elif isinstance(variable, TupleVariable): + if not variable.index in tuple_variables_instances: + new_variable = TupleVariableSSA(variable) + new_variable.set_type(variable.type) + tuple_variables_instances[variable.index] = new_variable + return tuple_variables_instances[variable.index] + assert isinstance(variable, (Constant, + SolidityVariable, + Contract, + Enum, + SolidityFunction, + Structure, + Function)) + return variable + +def get_variable(ir, f, *instances): + variable = f(ir) + variable = get(variable, *instances) + return variable + +def _get_traversal(values, *instances): + ret = [] + for v in values: + if isinstance(v, list): + v = _get_traversal(v, *instances) + else: + v = get(v, *instances) + ret.append(v) + return ret + +def get_arguments(ir, *instances): + return _get_traversal(ir.arguments, *instances) + +def get_rec_values(ir, f, *instances): + # Use by InitArray and NewArray + # Potential recursive array(s) + ori_init_values = f(ir) + + return _get_traversal(ori_init_values, *instances) + +def copy_ir(ir, *instances): ''' Args: ir (Operation) @@ -427,213 +507,156 @@ def copy_ir(ir, local_variables_instances, state_variables_instances, temporary_ Note: temporary and reference can be indexed by int, as they dont need phi functions ''' - - def get(variable): - if isinstance(variable, LocalVariable): - if variable.name in local_variables_instances: - return local_variables_instances[variable.name] - new_var = LocalIRVariable(variable) - local_variables_instances[variable.name] = new_var - all_local_variables_instances[variable.name] = new_var - return new_var - if isinstance(variable, StateVariable) and variable.canonical_name in state_variables_instances: - return state_variables_instances[variable.canonical_name] - elif isinstance(variable, ReferenceVariable): - if not variable.index in reference_variables_instances: - new_variable = ReferenceVariable(variable.node, index=variable.index) - if variable.points_to: - new_variable.points_to = get(variable.points_to) - new_variable.set_type(variable.type) - reference_variables_instances[variable.index] = new_variable - return reference_variables_instances[variable.index] - elif isinstance(variable, TemporaryVariable): - if not variable.index in temporary_variables_instances: - new_variable = TemporaryVariable(variable.node, index=variable.index) - new_variable.set_type(variable.type) - temporary_variables_instances[variable.index] = new_variable - return temporary_variables_instances[variable.index] - return variable - - def get_variable(ir, f): - variable = f(ir) - variable = get(variable) - return variable - - def get_arguments(ir): - arguments = [] - for arg in ir.arguments: - arg = get(arg) - arguments.append(arg) - return arguments - - def get_rec_values(ir, f): - # Use by InitArray and NewArray - # Potential recursive array(s) - ori_init_values = f(ir) - - def traversal(values): - ret = [] - for v in values: - if isinstance(v, list): - v = traversal(v) - else: - v = get(v) - ret.append(v) - return ret - - return traversal(ori_init_values) - - if isinstance(ir, Assignment): - lvalue = get_variable(ir, lambda x: ir.lvalue) - rvalue = get_variable(ir, lambda x: ir.rvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + rvalue = get_variable(ir, lambda x: x.rvalue, *instances) variable_return_type = ir.variable_return_type return Assignment(lvalue, rvalue, variable_return_type) elif isinstance(ir, Balance): - lvalue = get_variable(ir, lambda x: ir.lvalue) - value = get_variable(ir, lambda x: ir.value) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + value = get_variable(ir, lambda x: x.value, *instances) return Balance(value, lvalue) elif isinstance(ir, Binary): - lvalue = get_variable(ir, lambda x: ir.lvalue) - variable_left = get_variable(ir, lambda x: ir.variable_left) - variable_right = get_variable(ir, lambda x: ir.variable_right) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + variable_left = get_variable(ir, lambda x: x.variable_left, *instances) + variable_right = get_variable(ir, lambda x: x.variable_right, *instances) operation_type = ir.type return Binary(lvalue, variable_left, variable_right, operation_type) elif isinstance(ir, Condition): - val = get_variable(ir, lambda x: ir.value) + val = get_variable(ir, lambda x: x.value, *instances) return Condition(val) elif isinstance(ir, Delete): - lvalue = get_variable(ir, lambda x: ir.lvalue) - variable = get_variable(ir, lambda x: ir.variable) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + variable = get_variable(ir, lambda x: x.variable, *instances) return Delete(lvalue, variable) elif isinstance(ir, EventCall): name = ir.name return EventCall(name) elif isinstance(ir, HighLevelCall): # include LibraryCall - destination = get_variable(ir, lambda x: ir.destination) + destination = get_variable(ir, lambda x: x.destination, *instances) function_name = ir.function_name nbr_arguments = ir.nbr_arguments - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call if isinstance(ir, LibraryCall): new_ir = LibraryCall(destination, function_name, nbr_arguments, lvalue, type_call) else: new_ir = HighLevelCall(destination, function_name, nbr_arguments, lvalue, type_call) new_ir.call_id = ir.call_id - new_ir.call_value = get_variable(ir, lambda x: ir.call_value) - new_ir.call_gas = get_variable(ir, lambda x: ir.call_gas) - new_ir.arguments = get_arguments(ir) + new_ir.call_value = get_variable(ir, lambda x: x.call_value, *instances) + new_ir.call_gas = get_variable(ir, lambda x: x.call_gas, *instances) + new_ir.arguments = get_arguments(ir, *instances) new_ir.function = ir.function return new_ir elif isinstance(ir, Index): - lvalue = get_variable(ir, lambda x: ir.lvalue) - variable_left = get_variable(ir, lambda x: ir.variable_left) - variable_right = get_variable(ir, lambda x: ir.variable_right) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + variable_left = get_variable(ir, lambda x: x.variable_left, *instances) + variable_right = get_variable(ir, lambda x: x.variable_right, *instances) index_type = ir.index_type return Index(lvalue, variable_left, variable_right, index_type) elif isinstance(ir, InitArray): - lvalue = get_variable(ir, lambda x: ir.lvalue) - init_values = get_rec_values(ir, lambda x: ir.init_values) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + init_values = get_rec_values(ir, lambda x: x.init_values, *instances) return InitArray(init_values, lvalue) elif isinstance(ir, InternalCall): function = ir.function nbr_arguments = ir.nbr_arguments - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call new_ir = InternalCall(function, nbr_arguments, lvalue, type_call) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, InternalDynamicCall): - lvalue = get_variable(ir, lambda x: ir.lvalue) - function = ir.function + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + function = get_variable(ir, lambda x: x.function, *instances) function_type = ir.function_type new_ir = InternalDynamicCall(lvalue, function, function_type) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, LowLevelCall): - destination = get_variable(ir, lambda x: x.destination) + destination = get_variable(ir, lambda x: x.destination, *instances) function_name = ir.function_name nbr_arguments = ir.nbr_arguments - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call new_ir = LowLevelCall(destination, function_name, nbr_arguments, lvalue, type_call) new_ir.call_id = ir.call_id - new_ir.call_value = get_variable(ir, lambda x: ir.call_value) - new_ir.call_gas = get_variable(ir, lambda x: ir.call_gas) - new_ir.arguments = get_arguments(ir) + new_ir.call_value = get_variable(ir, lambda x: x.call_value, *instances) + new_ir.call_gas = get_variable(ir, lambda x: x.call_gas, *instances) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, Member): - lvalue = get_variable(ir, lambda x: ir.lvalue) - variable_left = get_variable(ir, lambda x: ir.variable_left) - variable_right = get_variable(ir, lambda x: ir.variable_right) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + variable_left = get_variable(ir, lambda x: x.variable_left, *instances) + variable_right = get_variable(ir, lambda x: x.variable_right, *instances) return Member(variable_left, variable_right, lvalue) elif isinstance(ir, NewArray): depth = ir.depth array_type = ir.array_type - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) new_ir = NewArray(depth, array_type, lvalue) - new_ir.arguments = get_rec_values(ir, lambda x: ir.arguments) + new_ir.arguments = get_rec_values(ir, lambda x: x.arguments, *instances) return new_ir elif isinstance(ir, NewElementaryType): new_type = ir.type - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) new_ir = NewElementaryType(new_type, lvalue) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, NewContract): contract_name = ir.contract_name - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) new_ir = NewContract(contract_name, lvalue) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, NewStructure): structure = ir.structure - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) new_ir = NewStructure(structure, lvalue) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, Push): - array = get_variable(ir, lambda x: ir.array) - lvalue = get_variable(ir, lambda x: ir.lvalue) + array = get_variable(ir, lambda x: x.array, *instances) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) return Push(array, lvalue) elif isinstance(ir, Return): - value = [get_variable(x, lambda y: y) for x in ir.values] - return Return(value) + values = get_rec_values(ir, lambda x: x.values, *instances) + return Return(values) elif isinstance(ir, Send): - destination = get_variable(ir, lambda x: ir.destination) - value = get_variable(ir, lambda x: ir.call_value) - lvalue = get_variable(ir, lambda x: ir.lvalue) + destination = get_variable(ir, lambda x: x.destination, *instances) + value = get_variable(ir, lambda x: x.call_value, *instances) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) return Send(destination, value, lvalue) elif isinstance(ir, SolidityCall): function = ir.function nbr_arguments = ir.nbr_arguments - lvalue = get_variable(ir, lambda x: ir.lvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call new_ir = SolidityCall(function, nbr_arguments, lvalue, type_call) - new_ir.arguments = get_arguments(ir) + new_ir.arguments = get_arguments(ir, *instances) return new_ir elif isinstance(ir, Transfer): - destination = get_variable(ir, lambda x: ir.destination) - value = get_variable(ir, lambda x: ir.call_value) + destination = get_variable(ir, lambda x: x.destination, *instances) + value = get_variable(ir, lambda x: x.call_value, *instances) return Transfer(destination, value) elif isinstance(ir, TypeConversion): - lvalue = get_variable(ir, lambda x: ir.lvalue) - variable = get_variable(ir, lambda x: ir.variable) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + variable = get_variable(ir, lambda x: x.variable, *instances) variable_type = ir.type return TypeConversion(lvalue, variable, variable_type) elif isinstance(ir, Unary): - lvalue = get_variable(ir, lambda x: ir.lvalue) - rvalue = get_variable(ir, lambda x: ir.rvalue) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + rvalue = get_variable(ir, lambda x: x.rvalue, *instances) operation_type = ir.type return Unary(lvalue, rvalue, operation_type) elif isinstance(ir, Unpack): - lvalue = get_variable(ir, lambda x: ir.lvalue) - tuple_var = ir.tuple + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + tuple_var = get_variable(ir, lambda x: x.tuple, *instances) idx = ir.index return Unpack(lvalue, tuple_var, idx) elif isinstance(ir, Length): - lvalue = get_variable(ir, lambda x: ir.lvalue) - value = get_variable(ir, lambda x: ir.value) + lvalue = get_variable(ir, lambda x: x.lvalue, *instances) + value = get_variable(ir, lambda x: x.value, *instances) return Length(value, lvalue) diff --git a/slither/slithir/variables/__init__.py b/slither/slithir/variables/__init__.py index 416d90108..624287318 100644 --- a/slither/slithir/variables/__init__.py +++ b/slither/slithir/variables/__init__.py @@ -1,6 +1,9 @@ from .constant import Constant from .reference import ReferenceVariable +from .reference_ssa import ReferenceVariableSSA from .temporary import TemporaryVariable +from .temporary_ssa import TemporaryVariableSSA from .tuple import TupleVariable +from .tuple_ssa import TupleVariableSSA from .local_variable import LocalIRVariable from .state_variable import StateIRVariable diff --git a/slither/slithir/variables/tuple.py b/slither/slithir/variables/tuple.py index d95c48e20..bfff48586 100644 --- a/slither/slithir/variables/tuple.py +++ b/slither/slithir/variables/tuple.py @@ -1,15 +1,21 @@ from .variable import SlithIRVariable from slither.core.variables.variable import Variable +from slither.core.children.child_node import ChildNode from slither.core.solidity_types.type import Type -class TupleVariable(SlithIRVariable): +class TupleVariable(ChildNode, SlithIRVariable): COUNTER = 0 - def __init__(self): + def __init__(self, node, index=None): super(TupleVariable, self).__init__() - self._index = TupleVariable.COUNTER - TupleVariable.COUNTER += 1 + if index is None: + self._index = TupleVariable.COUNTER + TupleVariable.COUNTER += 1 + else: + self._index = index + + self._node = node @property def index(self): diff --git a/slither/slithir/variables/tuple_ssa.py b/slither/slithir/variables/tuple_ssa.py new file mode 100644 index 000000000..04c050260 --- /dev/null +++ b/slither/slithir/variables/tuple_ssa.py @@ -0,0 +1,20 @@ +''' + This class is used for the SSA version of slithIR + It is similar to the non-SSA version of slithIR + as the TupleVariable are in SSA form in both version +''' +from .tuple import TupleVariable +from .variable import SlithIRVariable + +class TupleVariableSSA(TupleVariable): + + def __init__(self, t): + super(TupleVariableSSA, self).__init__(t.node, t.index) + + self._non_ssa_version = t + + + @property + def non_ssa_version(self): + return self._non_ssa_version + diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index fd191df56..a1f682f88 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -128,7 +128,7 @@ class ExpressionToSlithIR(ExpressionVisitor): # If tuple if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()': - val = TupleVariable() + val = TupleVariable(self._node) else: val = TemporaryVariable(self._node) internal_call = InternalCall(called, len(args), val, expression.type_call) @@ -139,7 +139,7 @@ class ExpressionToSlithIR(ExpressionVisitor): # If tuple if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()': - val = TupleVariable() + val = TupleVariable(self._node) else: val = TemporaryVariable(self._node) From a7cfcf7ae81a4d81ada8790d9836f3e86ca4ca33 Mon Sep 17 00:00:00 2001 From: Josselin Date: Tue, 12 Feb 2019 17:34:02 +0000 Subject: [PATCH 8/8] Add missing files Temporary and Reference variable have a specific classes for the SSA slithIR version --- slither/slithir/variables/reference_ssa.py | 18 ++++++++++++++++++ slither/slithir/variables/temporary_ssa.py | 20 ++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 slither/slithir/variables/reference_ssa.py create mode 100644 slither/slithir/variables/temporary_ssa.py diff --git a/slither/slithir/variables/reference_ssa.py b/slither/slithir/variables/reference_ssa.py new file mode 100644 index 000000000..b8c10993c --- /dev/null +++ b/slither/slithir/variables/reference_ssa.py @@ -0,0 +1,18 @@ +''' + This class is used for the SSA version of slithIR + It is similar to the non-SSA version of slithIR + as the ReferenceVariable are in SSA form in both version +''' +from .reference import ReferenceVariable +from .variable import SlithIRVariable + +class ReferenceVariableSSA(ReferenceVariable): + + def __init__(self, reference): + super(ReferenceVariableSSA, self).__init__(reference.node, reference.index) + + self._non_ssa_version = reference + + @property + def non_ssa_version(self): + return self._non_ssa_version diff --git a/slither/slithir/variables/temporary_ssa.py b/slither/slithir/variables/temporary_ssa.py new file mode 100644 index 000000000..b36e73419 --- /dev/null +++ b/slither/slithir/variables/temporary_ssa.py @@ -0,0 +1,20 @@ +''' + This class is used for the SSA version of slithIR + It is similar to the non-SSA version of slithIR + as the TemporaryVariable are in SSA form in both version +''' +from .temporary import TemporaryVariable +from .variable import SlithIRVariable + +class TemporaryVariableSSA(TemporaryVariable): + + def __init__(self, temporary): + super(TemporaryVariableSSA, self).__init__(temporary.node, temporary.index) + + self._non_ssa_version = temporary + + + @property + def non_ssa_version(self): + return self._non_ssa_version +