diff --git a/slither/core/children/child_expression.py b/slither/core/children/child_expression.py index e69de29bb..f918e7a52 100644 --- a/slither/core/children/child_expression.py +++ b/slither/core/children/child_expression.py @@ -0,0 +1,12 @@ + +class ChildExpression: + def __init__(self): + super(ChildExpression, self).__init__() + self._expression = None + + def set_expression(self, expression): + self._expression = expression + + @property + def expression(self): + return self._expression diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 63284db77..a41ccd098 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -45,10 +45,14 @@ def convert_expression(expression, node): if isinstance(expression, Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]: cst = Constant(expression.value, expression.type) - result = [Condition(cst)] + cond = Condition(cst) + cond.set_expression(expression) + result = [cond] return result if isinstance(expression, Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]: - result = [Condition(expression.value)] + cond = Condition(expression.value) + cond.set_expression(expression) + result = [cond] return result @@ -60,11 +64,15 @@ def convert_expression(expression, node): if result: if node.type in [NodeType.IF, NodeType.IFLOOP]: assert isinstance(result[-1], (OperationWithLValue)) - result.append(Condition(result[-1].lvalue)) + cond = Condition(result[-1].lvalue) + cond.set_expression(expression) + result.append(cond) elif node.type == NodeType.RETURN: # May return None if isinstance(result[-1], (OperationWithLValue)): - result.append(Return(result[-1].lvalue)) + r = Return(result[-1].lvalue) + r.set_expression(expression) + result.append(r) return result @@ -326,6 +334,7 @@ def _convert_type_contract(ir, slither): assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType('bytes')) + assignment.set_expression(ir.expression) assignment.lvalue.set_type(ElementaryType('bytes')) return assignment if ir.variable_right == 'runtimeCode': @@ -338,12 +347,14 @@ def _convert_type_contract(ir, slither): assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType('bytes')) + assignment.set_expression(ir.expression) assignment.lvalue.set_type(ElementaryType('bytes')) return assignment if ir.variable_right == 'name': assignment = Assignment(ir.lvalue, Constant(contract.name), ElementaryType('string')) + assignment.set_expression(ir.expression) assignment.lvalue.set_type(ElementaryType('string')) return assignment @@ -441,14 +452,18 @@ def propagate_types(ir, node): # TODO we should convert the reference to a temporary if the member is a length or a balance if ir.variable_right == 'length' and not isinstance(ir.variable_left, Contract) and isinstance(ir.variable_left.type, (ElementaryType, ArrayType)): length = Length(ir.variable_left, ir.lvalue) + length.set_expression(ir.expression) length.lvalue.points_to = ir.variable_left return length if ir.variable_right == 'balance'and not isinstance(ir.variable_left, Contract) and isinstance(ir.variable_left.type, ElementaryType): - return Balance(ir.variable_left, ir.lvalue) + b = Balance(ir.variable_left, ir.lvalue) + b.set_expression(ir.expression) + return b if ir.variable_right == 'selector' and isinstance(ir.variable_left.type, Function): assignment = Assignment(ir.lvalue, Constant(str(get_function_id(ir.variable_left.type.full_name))), ElementaryType('bytes4')) + assignment.set_expression(ir.expression) assignment.lvalue.set_type(ElementaryType('bytes4')) return assignment if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type, TypeInformation): @@ -529,6 +544,7 @@ def extract_tmp_call(ins, contract): if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType): call = InternalDynamicCall(ins.lvalue, ins.called, ins.called.type) + call.set_expression(ins.expression) call.call_id = ins.call_id return call if isinstance(ins.ori, Member): @@ -536,23 +552,28 @@ def extract_tmp_call(ins, contract): if ins.ori.variable_left in contract.inheritance + [contract]: if str(ins.ori.variable_right) in [f.name for f in contract.functions]: internalcall = InternalCall((ins.ori.variable_right, ins.ori.variable_left.name), ins.nbr_arguments, ins.lvalue, ins.type_call) + internalcall.set_expression(ins.expression) internalcall.call_id = ins.call_id return internalcall if str(ins.ori.variable_right) in [f.name for f in contract.events]: eventcall = EventCall(ins.ori.variable_right) + eventcall.set_expression(ins.expression) eventcall.call_id = ins.call_id return eventcall if isinstance(ins.ori.variable_left, Contract): st = ins.ori.variable_left.get_structure_from_name(ins.ori.variable_right) if st: op = NewStructure(st, ins.lvalue) + op.set_expression(ins.expression) op.call_id = ins.call_id return op libcall = LibraryCall(ins.ori.variable_left, ins.ori.variable_right, ins.nbr_arguments, ins.lvalue, ins.type_call) + libcall.set_expression(ins.expression) libcall.call_id = ins.call_id return libcall msgcall = HighLevelCall(ins.ori.variable_left, ins.ori.variable_right, ins.nbr_arguments, ins.lvalue, ins.type_call) msgcall.call_id = ins.call_id + msgcall.set_expression(ins.expression) return msgcall if isinstance(ins.ori, TmpCall): @@ -562,29 +583,42 @@ def extract_tmp_call(ins, contract): if str(ins.called) == 'block.blockhash': ins.called = SolidityFunction('blockhash(uint256)') elif str(ins.called) == 'this.balance': - return SolidityCall(SolidityFunction('this.balance()'), ins.nbr_arguments, ins.lvalue, ins.type_call) + s = SolidityCall(SolidityFunction('this.balance()'), ins.nbr_arguments, ins.lvalue, ins.type_call) + s.set_expression(ins.expression) + return s if isinstance(ins.called, SolidityFunction): - return SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call) + s = SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call) + s.set_expression(ins.expression) + return s if isinstance(ins.ori, TmpNewElementaryType): - return NewElementaryType(ins.ori.type, ins.lvalue) + n = NewElementaryType(ins.ori.type, ins.lvalue) + n.set_expression(ins.expression) + return n if isinstance(ins.ori, TmpNewContract): op = NewContract(Constant(ins.ori.contract_name), ins.lvalue) + op.set_expression(ins.expression) op.call_id = ins.call_id return op if isinstance(ins.ori, TmpNewArray): - return NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue) + n = NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue) + n.set_expression(ins.expression) + return n if isinstance(ins.called, Structure): op = NewStructure(ins.called, ins.lvalue) + op.set_expression(ins.expression) op.call_id = ins.call_id + op.set_expression(ins.expression) return op if isinstance(ins.called, Event): - return EventCall(ins.called.name) + e = EventCall(ins.called.name) + e.set_expression(ins.expression) + return e raise Exception('Not extracted {} {}'.format(type(ins.called), ins)) @@ -606,11 +640,15 @@ def convert_to_low_level(ir): """ if ir.function_name == 'transfer': assert len(ir.arguments) == 1 + prev_ir = ir ir = Transfer(ir.destination, ir.arguments[0]) + ir.set_expression(prev_ir.expression) return ir elif ir.function_name == 'send': assert len(ir.arguments) == 1 + prev_ir = ir ir = Send(ir.destination, ir.arguments[0], ir.lvalue) + ir.set_expression(prev_ir.expression) ir.lvalue.set_type(ElementaryType('bool')) return ir elif ir.destination.name == 'abi' and ir.function_name in ['encode', @@ -622,6 +660,7 @@ def convert_to_low_level(ir): call = SolidityFunction('abi.{}()'.format(ir.function_name)) new_ir = SolidityCall(call, ir.nbr_arguments, ir.lvalue, ir.type_call) new_ir.arguments = ir.arguments + new_ir.set_expression(ir.expression) if isinstance(call.return_type, list) and len(call.return_type) == 1: new_ir.lvalue.set_type(call.return_type[0]) else: @@ -640,6 +679,7 @@ def convert_to_low_level(ir): new_ir.call_value = ir.call_value new_ir.arguments = ir.arguments new_ir.lvalue.set_type(ElementaryType('bool')) + new_ir.set_expression(ir.expression) return new_ir raise SlithIRError('Incorrect conversion to low level {}'.format(ir)) @@ -662,9 +702,12 @@ def convert_to_push(ir, node): val = TemporaryVariable(node) operation = InitArray(ir.arguments[0], val) + operation.set_expression(ir.expression) ret.append(operation) + prev_ir = ir ir = Push(ir.destination, val) + ir.set_expression(prev_ir.expression) length = Literal(len(operation.init_values), 'uint256') t = operation.init_values[0].type @@ -674,18 +717,22 @@ def convert_to_push(ir, node): if lvalue: length = Length(ir.array, lvalue) + length.set_expression(ir.expression) length.lvalue.points_to = ir.lvalue ret.append(length) return ret + prev_ir = ir ir = Push(ir.destination, ir.arguments[0]) + ir.set_expression(prev_ir.expression) if lvalue: ret = [] ret.append(ir) length = Length(ir.array, lvalue) + length.set_expression(ir.expression) length.lvalue.points_to = ir.lvalue ret.append(length) return ret @@ -701,6 +748,7 @@ def look_for_library(contract, ir, node, using_for, t): ir.nbr_arguments, ir.lvalue, ir.type_call) + lib_call.set_expression(ir.expression) lib_call.call_gas = ir.call_gas lib_call.arguments = [ir.destination] + ir.arguments new_ir = convert_type_library_call(lib_call, lib_contract) diff --git a/slither/slithir/operations/operation.py b/slither/slithir/operations/operation.py index b127bd715..636921fe3 100644 --- a/slither/slithir/operations/operation.py +++ b/slither/slithir/operations/operation.py @@ -1,5 +1,6 @@ import abc from slither.core.context.context import Context +from slither.core.children.child_expression import ChildExpression from slither.core.children.child_node import ChildNode from slither.utils.utils import unroll @@ -21,7 +22,7 @@ class AbstractOperation(abc.ABC): """ pass -class Operation(Context, ChildNode, AbstractOperation): +class Operation(Context, ChildExpression, ChildNode, AbstractOperation): @property def used(self): diff --git a/slither/slithir/operations/phi.py b/slither/slithir/operations/phi.py index a11dfa139..e0d007b0f 100644 --- a/slither/slithir/operations/phi.py +++ b/slither/slithir/operations/phi.py @@ -1,10 +1,6 @@ -import logging from slither.slithir.operations.lvalue import OperationWithLValue -from slither.core.variables.variable import Variable -from slither.slithir.variables import TupleVariable -from slither.core.declarations.function import Function -from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue +from slither.slithir.utils.utils import is_valid_lvalue class Phi(OperationWithLValue): diff --git a/slither/slithir/utils/ssa.py b/slither/slithir/utils/ssa.py index fde9f5eba..4049e5cab 100644 --- a/slither/slithir/utils/ssa.py +++ b/slither/slithir/utils/ssa.py @@ -181,6 +181,8 @@ def generate_ssa_irs(node, local_variables_instances, all_local_variables_instan tuple_variables_instances, all_local_variables_instances) + new_ir.set_expression(ir.expression) + update_lvalue(new_ir, node, local_variables_instances, diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 7799cf128..5ad663e8c 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -83,6 +83,7 @@ class ExpressionToSlithIR(ExpressionVisitor): for idx in range(len(left)): if not left[idx] is None: operation = convert_assignment(left[idx], right[idx], expression.type, expression.expression_return_type) + operation.set_expression(expression) self._result.append(operation) set_val(expression, None) else: @@ -90,6 +91,7 @@ class ExpressionToSlithIR(ExpressionVisitor): for idx in range(len(left)): if not left[idx] is None: operation = Unpack(left[idx], right, idx) + operation.set_expression(expression) self._result.append(operation) set_val(expression, None) else: @@ -97,10 +99,12 @@ class ExpressionToSlithIR(ExpressionVisitor): # uint8[2] var = [1,2]; if isinstance(right, list): operation = InitArray(right, left) + operation.set_expression(expression) self._result.append(operation) set_val(expression, left) else: operation = convert_assignment(left, right, expression.type, expression.expression_return_type) + operation.set_expression(expression) self._result.append(operation) # Return left to handle # a = b = 1; @@ -112,6 +116,7 @@ class ExpressionToSlithIR(ExpressionVisitor): val = TemporaryVariable(self._node) operation = Binary(val, left, right, expression.type) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) @@ -130,11 +135,10 @@ class ExpressionToSlithIR(ExpressionVisitor): else: val = TemporaryVariable(self._node) internal_call = InternalCall(called, len(args), val, expression.type_call) + internal_call.set_expression(expression) self._result.append(internal_call) set_val(expression, val) else: - val = TemporaryVariable(self._node) - # If tuple if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()': val = TupleVariable(self._node) @@ -142,6 +146,7 @@ class ExpressionToSlithIR(ExpressionVisitor): val = TemporaryVariable(self._node) message_call = TmpCall(called, len(args), val, expression.type_call) + message_call.set_expression(expression) self._result.append(message_call) set_val(expression, val) @@ -165,8 +170,10 @@ class ExpressionToSlithIR(ExpressionVisitor): init_array_right = left left = init_array_val operation = InitArray(init_array_right, init_array_val) + operation.set_expression(expression) self._result.append(operation) operation = Index(val, left, right, expression.type) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) @@ -178,18 +185,21 @@ class ExpressionToSlithIR(ExpressionVisitor): expr = get(expression.expression) val = ReferenceVariable(self._node) member = Member(expr, Constant(expression.member_name), val) + member.set_expression(expression) self._result.append(member) set_val(expression, val) def _post_new_array(self, expression): val = TemporaryVariable(self._node) operation = TmpNewArray(expression.depth, expression.array_type, val) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) def _post_new_contract(self, expression): val = TemporaryVariable(self._node) operation = TmpNewContract(expression.contract_name, val) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) @@ -197,6 +207,7 @@ class ExpressionToSlithIR(ExpressionVisitor): # TODO unclear if this is ever used? val = TemporaryVariable(self._node) operation = TmpNewElementaryType(expression.type, val) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) @@ -212,6 +223,7 @@ class ExpressionToSlithIR(ExpressionVisitor): expr = get(expression.expression) val = TemporaryVariable(self._node) operation = TypeConversion(val, expr, expression.type) + operation.set_expression(expression) self._result.append(operation) set_val(expression, val) @@ -220,32 +232,40 @@ class ExpressionToSlithIR(ExpressionVisitor): if expression.type in [UnaryOperationType.BANG, UnaryOperationType.TILD]: lvalue = TemporaryVariable(self._node) operation = Unary(lvalue, value, expression.type) + operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.DELETE]: operation = Delete(value, value) + operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.PLUSPLUS_PRE]: operation = Binary(value, value, Constant("1"), BinaryType.ADDITION) + operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.MINUSMINUS_PRE]: operation = Binary(value, value, Constant("1"), BinaryType.SUBTRACTION) + operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.PLUSPLUS_POST]: lvalue = TemporaryVariable(self._node) operation = Assignment(lvalue, value, value.type) + operation.set_expression(expression) self._result.append(operation) operation = Binary(value, value, Constant("1"), BinaryType.ADDITION) + operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.MINUSMINUS_POST]: lvalue = TemporaryVariable(self._node) operation = Assignment(lvalue, value, value.type) + operation.set_expression(expression) self._result.append(operation) operation = Binary(value, value, Constant("1"), BinaryType.SUBTRACTION) + operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.PLUS_PRE]: @@ -253,6 +273,7 @@ class ExpressionToSlithIR(ExpressionVisitor): elif expression.type in [UnaryOperationType.MINUS_PRE]: lvalue = TemporaryVariable(self._node) operation = Binary(lvalue, Constant("0"), value, BinaryType.SUBTRACTION) + operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) else: diff --git a/utils/slither_format/utils/usages.py b/utils/slither_format/utils/usages.py deleted file mode 100644 index e69de29bb..000000000