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))
Exemple #3
0
    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)})"
            )