def copy_expression(self, expression, true_expression, false_expression): if self.condition: return if isinstance(expression, ConditionalExpression): raise SlitherException('Nested ternary operator not handled') if isinstance(expression, (Literal, Identifier, IndexAccess, NewArray, NewContract)): return None # case of lib # (.. ? .. : ..).add if isinstance(expression, MemberAccess): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression(next_expr, true_expression.expression, false_expression.expression) elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] for next_expr in expression.expressions: if self.apply_copy(next_expr, true_expression, false_expression, f_expressions): # always on last arguments added self.copy_expression(next_expr, true_expression.expressions[-1], false_expression.expressions[-1]) elif isinstance(expression, CallExpression): next_expr = expression.called # case of lib # (.. ? .. : ..).add if self.apply_copy(next_expr, true_expression, false_expression, f_called): self.copy_expression(next_expr, true_expression.called, false_expression.called) true_expression._arguments = [] false_expression._arguments = [] for next_expr in expression.arguments: if self.apply_copy(next_expr, true_expression, false_expression, f_call): # always on last arguments added self.copy_expression(next_expr, true_expression.arguments[-1], false_expression.arguments[-1]) elif isinstance(expression, TypeConversion): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression(expression.expression, true_expression.expression, false_expression.expression) else: raise SlitherException('Ternary operation not handled {}({})'.format(expression, type(expression)))
def _find_read_write_call(self): # pylint: disable=too-many-statements for ir in self.irs: self._slithir_vars |= { v for v in ir.read if self._is_valid_slithir_var(v) } if isinstance(ir, OperationWithLValue): var = ir.lvalue if var and self._is_valid_slithir_var(var): self._slithir_vars.add(var) if not isinstance(ir, (Phi, Index, Member)): self._vars_read += [ v for v in ir.read if self._is_non_slithir_var(v) ] for var in ir.read: if isinstance(var, ReferenceVariable): self._vars_read.append(var.points_to_origin) elif isinstance(ir, (Member, Index)): var = ir.variable_left if isinstance( ir, Member) else ir.variable_right if self._is_non_slithir_var(var): self._vars_read.append(var) if isinstance(var, ReferenceVariable): origin = var.points_to_origin if self._is_non_slithir_var(origin): self._vars_read.append(origin) if isinstance(ir, OperationWithLValue): if isinstance(ir, (Index, Member, Length)): continue # Don't consider Member and Index operations -> ReferenceVariable var = ir.lvalue if isinstance(var, ReferenceVariable): var = var.points_to_origin if var and self._is_non_slithir_var(var): self._vars_written.append(var) if isinstance(ir, InternalCall): self._internal_calls.append(ir.function) if isinstance(ir, SolidityCall): # TODO: consider removing dependancy of solidity_call to internal_call self._solidity_calls.append(ir.function) self._internal_calls.append(ir.function) if isinstance(ir, LowLevelCall): assert isinstance(ir.destination, (Variable, SolidityVariable)) self._low_level_calls.append( (ir.destination, ir.function_name.value)) 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: try: self._high_level_calls.append( (ir.destination.type.type, ir.function)) except AttributeError as error: # pylint: disable=raise-missing-from raise SlitherException( f"Function not found on IR: {ir}.\nNode: {self} ({self.source_mapping_str})\nFunction: {self.function}\nPlease try compiling with a recent Solidity version. {error}" ) elif isinstance(ir, LibraryCall): assert isinstance(ir.destination, Contract) self._high_level_calls.append((ir.destination, ir.function)) self._library_calls.append((ir.destination, ir.function)) self._vars_read = list(set(self._vars_read)) self._state_vars_read = [ v for v in self._vars_read if isinstance(v, StateVariable) ] self._local_vars_read = [ v for v in self._vars_read if isinstance(v, LocalVariable) ] self._solidity_vars_read = [ v for v in self._vars_read if isinstance(v, SolidityVariable) ] self._vars_written = list(set(self._vars_written)) self._state_vars_written = [ v for v in self._vars_written if isinstance(v, StateVariable) ] self._local_vars_written = [ v for v in self._vars_written if isinstance(v, LocalVariable) ] self._internal_calls = list(set(self._internal_calls)) self._solidity_calls = list(set(self._solidity_calls)) self._high_level_calls = list(set(self._high_level_calls)) self._library_calls = list(set(self._library_calls)) self._low_level_calls = list(set(self._low_level_calls))
def _find_read_write_call(self): for ir in self.irs: self._slithir_vars |= set([v for v in ir.read if self._is_valid_slithir_var(v)]) if isinstance(ir, OperationWithLValue): var = ir.lvalue if var and self._is_valid_slithir_var(var): self._slithir_vars.add(var) if not isinstance(ir, (Phi, Index, Member)): self._vars_read += [v for v in ir.read if self._is_non_slithir_var(v)] for var in ir.read: if isinstance(var, (ReferenceVariable)): self._vars_read.append(var.points_to_origin) elif isinstance(ir, (Member, Index)): var = ir.variable_left if isinstance(ir, Member) else ir.variable_right if self._is_non_slithir_var(var): self._vars_read.append(var) if isinstance(var, (ReferenceVariable)): origin = var.points_to_origin if self._is_non_slithir_var(origin): self._vars_read.append(origin) if isinstance(ir, OperationWithLValue): if isinstance(ir, (Index, Member, Length, Balance)): continue # Don't consider Member and Index operations -> ReferenceVariable var = ir.lvalue if isinstance(var, (ReferenceVariable)): var = var.points_to_origin if var and self._is_non_slithir_var(var): self._vars_written.append(var) if isinstance(ir, InternalCall): self._internal_calls.append(ir.function) if isinstance(ir, SolidityCall): # TODO: consider removing dependancy of solidity_call to internal_call self._solidity_calls.append(ir.function) self._internal_calls.append(ir.function) if isinstance(ir, LowLevelCall): assert isinstance(ir.destination, (Variable, SolidityVariable)) self._low_level_calls.append((ir.destination, ir.function_name.value)) 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: try: self._high_level_calls.append((ir.destination.type.type, ir.function)) except AttributeError: raise SlitherException(f'Function not found on {ir}. Please try compiling with a recent Solidity version.') elif isinstance(ir, LibraryCall): assert isinstance(ir.destination, Contract) self._high_level_calls.append((ir.destination, ir.function)) self._library_calls.append((ir.destination, ir.function)) self._vars_read = list(set(self._vars_read)) self._state_vars_read = [v for v in self._vars_read if isinstance(v, StateVariable)] self._local_vars_read = [v for v in self._vars_read if isinstance(v, LocalVariable)] self._solidity_vars_read = [v for v in self._vars_read if isinstance(v, SolidityVariable)] self._vars_written = list(set(self._vars_written)) self._state_vars_written = [v for v in self._vars_written if isinstance(v, StateVariable)] self._local_vars_written = [v for v in self._vars_written if isinstance(v, LocalVariable)] self._internal_calls = list(set(self._internal_calls)) self._solidity_calls = list(set(self._solidity_calls)) self._high_level_calls = list(set(self._high_level_calls)) self._library_calls = list(set(self._library_calls)) self._low_level_calls = list(set(self._low_level_calls))
def copy_expression(self, expression: Expression, true_expression: Expression, false_expression: Expression) -> None: if self.condition: return if isinstance(expression, ConditionalExpression): raise SlitherException("Nested ternary operator not handled") if isinstance( expression, (Literal, Identifier, IndexAccess, NewArray, NewContract)): return # case of lib # (.. ? .. : ..).add if isinstance(expression, MemberAccess): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression(next_expr, true_expression.expression, false_expression.expression) elif isinstance( expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] for next_expr in expression.expressions: if isinstance(next_expr, IndexAccess): # create an index access for each branch if isinstance(next_expr.expression_right, ConditionalExpression): next_expr = _handle_ternary_access( next_expr, true_expression, false_expression) if self.apply_copy(next_expr, true_expression, false_expression, f_expressions): # always on last arguments added self.copy_expression( next_expr, true_expression.expressions[-1], false_expression.expressions[-1], ) elif isinstance(expression, CallExpression): next_expr = expression.called # case of lib # (.. ? .. : ..).add if self.apply_copy(next_expr, true_expression, false_expression, f_called): self.copy_expression(next_expr, true_expression.called, false_expression.called) true_expression._arguments = [] false_expression._arguments = [] for next_expr in expression.arguments: if self.apply_copy(next_expr, true_expression, false_expression, f_call): # always on last arguments added self.copy_expression( next_expr, true_expression.arguments[-1], false_expression.arguments[-1], ) elif isinstance(expression, (TypeConversion, UnaryOperation)): next_expr = expression.expression if self.apply_copy(next_expr, true_expression, false_expression, f_expression): self.copy_expression( expression.expression, true_expression.expression, false_expression.expression, ) else: raise SlitherException( f"Ternary operation not handled {expression}({type(expression)})" )