Exemple #1
0
def _convert_type_contract(ir, slither):
    assert isinstance(ir.variable_left.type, TypeInformation)
    contract = ir.variable_left.type.type

    if ir.variable_right == 'creationCode':
        if slither.crytic_compile:
            bytecode = slither.crytic_compile.bytecode_init(contract.name)
        else:
            logger.info(
                'The codebase uses type(x).creationCode, but crytic-compile was not used. As a result, the bytecode cannot be found'
            )
            bytecode = "MISSING_BYTECODE"
        assignment = Assignment(ir.lvalue, Constant(str(bytecode)),
                                ElementaryType('bytes'))
        assignment.lvalue.set_type(ElementaryType('bytes'))
        return assignment
    if ir.variable_right == 'runtimeCode':
        if slither.crytic_compile:
            bytecode = slither.crytic_compile.bytecode_runtime(contract.name)
        else:
            logger.info(
                'The codebase uses type(x).runtimeCode, but crytic-compile was not used. As a result, the bytecode cannot be found'
            )
            bytecode = "MISSING_BYTECODE"
        assignment = Assignment(ir.lvalue, Constant(str(bytecode)),
                                ElementaryType('bytes'))
        assignment.lvalue.set_type(ElementaryType('bytes'))
        return assignment
    if ir.variable_right == 'name':
        assignment = Assignment(ir.lvalue, Constant(contract.name),
                                ElementaryType('string'))
        assignment.lvalue.set_type(ElementaryType('string'))
        return assignment

    raise SlithIRError(f'type({contract.name}).{ir.variable_right} is unknown')
Exemple #2
0
def convert_expression(expression, node):
    # handle standlone expression
    # such as return true;
    from slither.core.cfg.node import NodeType
    if isinstance(expression, Literal) and node.type == NodeType.RETURN:
        result = [Return(Constant(expression.value))]
        return result
    if isinstance(expression, Identifier) and node.type == NodeType.RETURN:
        result = [Return(expression.value)]
        return result
    if isinstance(expression,
                  Literal) and node.type in [NodeType.IF, NodeType.IFLOOP]:
        result = [Condition(Constant(expression.value))]
        return result
    if isinstance(expression,
                  Identifier) and node.type in [NodeType.IF, NodeType.IFLOOP]:
        result = [Condition(expression.value)]
        return result
    visitor = ExpressionToSlithIR(expression)
    result = visitor.result()

    result = apply_ir_heuristics(result, node)

    if result:
        if node.type in [NodeType.IF, NodeType.IFLOOP]:
            assert isinstance(result[-1], (OperationWithLValue))
            result.append(Condition(result[-1].lvalue))
        elif node.type == NodeType.RETURN:
            # May return None
            if isinstance(result[-1], (OperationWithLValue)):
                result.append(Return(result[-1].lvalue))

    return result
Exemple #3
0
    def _post_member_access(self, expression):
        expr = get(expression.expression)

        # Look for type(X).max / min
        # Because we looked at the AST structure, we need to look into the nested expression
        # Hopefully this is always on a direct sub field, and there is no weird construction
        if isinstance(expression.expression, CallExpression) and expression.member_name in [
            "min",
            "max",
        ]:
            if isinstance(expression.expression.called, Identifier):
                if expression.expression.called.value == SolidityFunction("type()"):
                    assert len(expression.expression.arguments) == 1
                    val = TemporaryVariable(self._node)
                    type_expression_found = expression.expression.arguments[0]
                    assert isinstance(type_expression_found, ElementaryTypeNameExpression)
                    type_found = type_expression_found.type
                    if expression.member_name == "min:":
                        op = Assignment(val, Constant(str(type_found.min), type_found), type_found,)
                    else:
                        op = Assignment(val, Constant(str(type_found.max), type_found), type_found,)
                    self._result.append(op)
                    set_val(expression, val)
                    return

        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_unary_operation(self, expression):
     value = get(expression.expression)
     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", value.type),
                            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", value.type),
                            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", value.type),
                            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", value.type),
                            BinaryType.SUBTRACTION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     elif expression.type in [UnaryOperationType.PLUS_PRE]:
         set_val(expression, value)
     elif expression.type in [UnaryOperationType.MINUS_PRE]:
         lvalue = TemporaryVariable(self._node)
         operation = Binary(lvalue, Constant("0", value.type), value,
                            BinaryType.SUBTRACTION)
         operation.set_expression(expression)
         self._result.append(operation)
         set_val(expression, lvalue)
     else:
         raise SlithIRError(
             'Unary operation to IR not supported {}'.format(expression))
Exemple #5
0
def extract_tmp_call(ins):
    assert isinstance(ins, TmpCall)

    if isinstance(ins.called, Variable) and isinstance(ins.called.type,
                                                       FunctionType):
        call = InternalDynamicCall(ins.lvalue, ins.called, ins.called.type)
        call.call_id = ins.call_id
        return call
    if isinstance(ins.ori, Member):
        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.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.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
        return msgcall

    if isinstance(ins.ori, TmpCall):
        r = extract_tmp_call(ins.ori)
        return r
    if isinstance(ins.called, SolidityVariableComposed):
        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)

    if isinstance(ins.called, SolidityFunction):
        return SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue,
                            ins.type_call)

    if isinstance(ins.ori, TmpNewElementaryType):
        return NewElementaryType(ins.ori.type, ins.lvalue)

    if isinstance(ins.ori, TmpNewContract):
        op = NewContract(Constant(ins.ori.contract_name), ins.lvalue)
        op.call_id = ins.call_id
        return op

    if isinstance(ins.ori, TmpNewArray):
        return NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue)

    if isinstance(ins.called, Structure):
        op = NewStructure(ins.called, ins.lvalue)
        op.call_id = ins.call_id
        return op

    if isinstance(ins.called, Event):
        return EventCall(ins.called.name)

    raise Exception('Not extracted {} {}'.format(type(ins.called), ins))
Exemple #6
0
 def _post_member_access(self, expression):
     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)
Exemple #7
0
def convert_to_pop(ir, node):
    """
    Convert pop operators
    Return a list of 6 operations
    """

    ret = []

    arr = ir.destination
    length = ReferenceVariable(node)
    length.set_type(ElementaryType('uint256'))

    ir_length = Length(arr, length)
    ir_length.set_expression(ir.expression)
    ir_length.set_node(ir.node)
    ir_length.lvalue.points_to = arr
    ret.append(ir_length)

    val = TemporaryVariable(node)

    ir_sub_1 = Binary(val, length, Constant("1", ElementaryType('uint256')),
                      BinaryType.SUBTRACTION)
    ir_sub_1.set_expression(ir.expression)
    ir_sub_1.set_node(ir.node)
    ret.append(ir_sub_1)

    element_to_delete = ReferenceVariable(node)
    ir_assign_element_to_delete = Index(element_to_delete, arr, val,
                                        ElementaryType('uint256'))
    ir_length.lvalue.points_to = arr
    element_to_delete.set_type(ElementaryType('uint256'))
    ir_assign_element_to_delete.set_expression(ir.expression)
    ir_assign_element_to_delete.set_node(ir.node)
    ret.append(ir_assign_element_to_delete)

    ir_delete = Delete(element_to_delete, element_to_delete)
    ir_delete.set_expression(ir.expression)
    ir_delete.set_node(ir.node)
    ret.append(ir_delete)

    length_to_assign = ReferenceVariable(node)
    length_to_assign.set_type(ElementaryType('uint256'))
    ir_length = Length(arr, length_to_assign)
    ir_length.set_expression(ir.expression)
    ir_length.lvalue.points_to = arr
    ir_length.set_node(ir.node)
    ret.append(ir_length)

    ir_assign_length = Assignment(length_to_assign, val,
                                  ElementaryType('uint256'))
    ir_assign_length.set_expression(ir.expression)
    ir_assign_length.set_node(ir.node)
    ret.append(ir_assign_length)

    return ret
    def _detect_boolean_constant_misuses(contract):  # pylint: disable=too-many-branches
        """
        Detects and returns all nodes which misuse a Boolean constant.
        :param contract: Contract to detect assignment within.
        :return: A list of misusing nodes.
        """

        # Create our result set.
        results = []

        # Loop for each function and modifier.
        for function in contract.functions_declared:  # pylint: disable=too-many-nested-blocks
            f_results = set()

            # Loop for every node in this function, looking for boolean constants
            for node in function.nodes:

                # Do not report "while(true)"
                if node.type == NodeType.IFLOOP:
                    if node.irs:
                        if len(node.irs) == 1:
                            ir = node.irs[0]
                            if isinstance(ir, Condition) and ir.value == Constant(
                                "True", ElementaryType("bool")
                            ):
                                continue

                for ir in node.irs:
                    if isinstance(ir, (Assignment, Call, Return, InitArray)):
                        # It's ok to use a bare boolean constant in these contexts
                        continue
                    if isinstance(ir, Binary):
                        if ir.type in [
                            BinaryType.ADDITION,
                            BinaryType.EQUAL,
                            BinaryType.NOT_EQUAL,
                        ]:
                            # Comparing to a Boolean constant is dubious style, but harmless
                            # Equal is catch by another detector (informational severity)
                            continue
                    for r in ir.read:
                        if isinstance(r, Constant):
                            if isinstance(r.value, bool):
                                f_results.add(node)
                results.append((function, f_results))

        # Return the resulting set of nodes with improper uses of Boolean constants
        return results
Exemple #9
0
 def _post_literal(self, expression):
     cst = Constant(expression.value, expression.type, expression.subdenomination)
     set_val(expression, cst)
Exemple #10
0
    def _post_call_expression(self, expression):
        called = get(expression.called)
        args = [get(a) for a in expression.arguments if a]
        for arg in args:
            arg_ = Argument(arg)
            arg_.set_expression(expression)
            self._result.append(arg_)
        if isinstance(called, Function):
            # internal call

            # If tuple
            if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()':
                val = TupleVariable(self._node)
            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:
            # yul things
            if called.name == 'caller()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('msg.sender'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'origin()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('tx.origin'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'extcodesize(uint256)':
                val = ReferenceVariable(self._node)
                var = Member(args[0], Constant('codesize'), val)
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'selfbalance()':
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable('this'), ElementaryType('address'))
                self._result.append(var)

                val1 = ReferenceVariable(self._node)
                var1 = Member(val, Constant('balance'), val1)
                self._result.append(var1)
                set_val(expression, val1)
            elif called.name == 'address()':
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable('this'), ElementaryType('address'))
                self._result.append(var)
                set_val(expression, val)
            elif called.name == 'callvalue()':
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed('msg.value'), 'uint256')
                self._result.append(var)
                set_val(expression, val)
            else:
                # If tuple
                if expression.type_call.startswith('tuple(') and expression.type_call != 'tuple()':
                    val = TupleVariable(self._node)
                else:
                    val = TemporaryVariable(self._node)

                message_call = TmpCall(called, len(args), val, expression.type_call)
                message_call.set_expression(expression)
                # Gas/value are only accessible here if the syntax {gas: , value: }
                # Is used over .gas().value()
                if expression.call_gas:
                    call_gas = get(expression.call_gas)
                    message_call.call_gas = call_gas
                if expression.call_value:
                    call_value = get(expression.call_value)
                    message_call.call_value = call_value
                if expression.call_salt:
                    call_salt = get(expression.call_salt)
                    message_call.call_salt = call_salt
                self._result.append(message_call)
                set_val(expression, val)
 def _post_literal(self, expression):
     set_val(expression, Constant(expression.value))
Exemple #12
0
def extract_tmp_call(ins, contract):
    assert isinstance(ins, TmpCall)

    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):
        # If there is a call on an inherited contract, it is an internal call or an event
        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

        if ins.call_gas:
            msgcall.call_gas = ins.call_gas
        if ins.call_value:
            msgcall.call_value = ins.call_value
        msgcall.set_expression(ins.expression)

        return msgcall

    if isinstance(ins.ori, TmpCall):
        r = extract_tmp_call(ins.ori, contract)
        r.set_node(ins.node)
        return r
    if isinstance(ins.called, SolidityVariableComposed):
        if str(ins.called) == 'block.blockhash':
            ins.called = SolidityFunction('blockhash(uint256)')
        elif str(ins.called) == 'this.balance':
            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):
        s = SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call)
        s.set_expression(ins.expression)
        return s

    if isinstance(ins.ori, TmpNewElementaryType):
        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):
        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):
        e = EventCall(ins.called.name)
        e.set_expression(ins.expression)
        return e

    if isinstance(ins.called, Contract):
        # Called a base constructor, where there is no constructor
        if ins.called.constructor is None:
            return Nop()
        # Case where:
        # contract A{ constructor(uint) }
        # contract B is A {}
        # contract C is B{ constructor() A(10) B() {}
        # C calls B(), which does not exist
        # Ideally we should compare here for the parameters types too
        if len(ins.called.constructor.parameters) != ins.nbr_arguments:
            return Nop()
        internalcall = InternalCall(ins.called.constructor, ins.nbr_arguments, ins.lvalue,
                                    ins.type_call)
        internalcall.call_id = ins.call_id
        internalcall.set_expression(ins.expression)
        return internalcall

    raise Exception('Not extracted {} {}'.format(type(ins.called), ins))
Exemple #13
0
def extract_tmp_call(ins, contract):
    assert isinstance(ins, TmpCall)

    if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType):
        call = InternalDynamicCall(ins.lvalue, ins.called, ins.called.type)
        call.call_id = ins.call_id
        return call
    if isinstance(ins.ori, Member):
        # If there is a call on an inherited contract, it is an internal call or an event
        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.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.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.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.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
        return msgcall

    if isinstance(ins.ori, TmpCall):
        r = extract_tmp_call(ins.ori, contract)
        return r
    if isinstance(ins.called, SolidityVariableComposed):
        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)

    if isinstance(ins.called, SolidityFunction):
        return SolidityCall(ins.called, ins.nbr_arguments, ins.lvalue, ins.type_call)

    if isinstance(ins.ori, TmpNewElementaryType):
        return NewElementaryType(ins.ori.type, ins.lvalue)

    if isinstance(ins.ori, TmpNewContract):
        op = NewContract(Constant(ins.ori.contract_name), ins.lvalue)
        op.call_id = ins.call_id
        return op

    if isinstance(ins.ori, TmpNewArray):
        return NewArray(ins.ori.depth, ins.ori.array_type, ins.lvalue)

    if isinstance(ins.called, Structure):
        op = NewStructure(ins.called, ins.lvalue)
        op.call_id = ins.call_id
        return op

    if isinstance(ins.called, Event):
        return EventCall(ins.called.name)

    if isinstance(ins.called, Contract):
        # Called a base constructor, where there is no constructor
        if ins.called.constructor is None:
            return Nop()
        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))
    def _post_call_expression(self, expression):  # pylint: disable=too-many-branches,too-many-statements
        called = get(expression.called)
        args = [get(a) for a in expression.arguments if a]
        for arg in args:
            arg_ = Argument(arg)
            arg_.set_expression(expression)
            self._result.append(arg_)
        if isinstance(called, Function):
            # internal call

            # If tuple
            if expression.type_call.startswith(
                    "tuple(") and expression.type_call != "tuple()":
                val = TupleVariable(self._node)
            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:
            # yul things
            if called.name == "caller()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("msg.sender"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "origin()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("tx.origin"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "extcodesize(uint256)":
                val = ReferenceVariable(self._node)
                var = Member(args[0], Constant("codesize"), val)
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "selfbalance()":
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable("this"),
                                     ElementaryType("address"))
                self._result.append(var)

                val1 = ReferenceVariable(self._node)
                var1 = Member(val, Constant("balance"), val1)
                self._result.append(var1)
                set_val(expression, val1)
            elif called.name == "address()":
                val = TemporaryVariable(self._node)
                var = TypeConversion(val, SolidityVariable("this"),
                                     ElementaryType("address"))
                self._result.append(var)
                set_val(expression, val)
            elif called.name == "callvalue()":
                val = TemporaryVariable(self._node)
                var = Assignment(val, SolidityVariableComposed("msg.value"),
                                 "uint256")
                self._result.append(var)
                set_val(expression, val)
            else:
                # If tuple
                if expression.type_call.startswith(
                        "tuple(") and expression.type_call != "tuple()":
                    val = TupleVariable(self._node)
                else:
                    val = TemporaryVariable(self._node)

                message_call = TmpCall(called, len(args), val,
                                       expression.type_call)
                message_call.set_expression(expression)
                # Gas/value are only accessible here if the syntax {gas: , value: }
                # Is used over .gas().value()
                if expression.call_gas:
                    call_gas = get(expression.call_gas)
                    message_call.call_gas = call_gas
                if expression.call_value:
                    call_value = get(expression.call_value)
                    message_call.call_value = call_value
                if expression.call_salt:
                    call_salt = get(expression.call_salt)
                    message_call.call_salt = call_salt
                self._result.append(message_call)
                set_val(expression, val)
    def _post_member_access(self, expression):
        expr = get(expression.expression)

        # Look for type(X).max / min
        # Because we looked at the AST structure, we need to look into the nested expression
        # Hopefully this is always on a direct sub field, and there is no weird construction
        if isinstance(expression.expression,
                      CallExpression) and expression.member_name in [
                          "min",
                          "max",
                      ]:
            if isinstance(expression.expression.called, Identifier):
                if expression.expression.called.value == SolidityFunction(
                        "type()"):
                    assert len(expression.expression.arguments) == 1
                    val = TemporaryVariable(self._node)
                    type_expression_found = expression.expression.arguments[0]
                    assert isinstance(type_expression_found,
                                      ElementaryTypeNameExpression)
                    type_found = type_expression_found.type
                    if expression.member_name == "min:":
                        op = Assignment(
                            val,
                            Constant(str(type_found.min), type_found),
                            type_found,
                        )
                    else:
                        op = Assignment(
                            val,
                            Constant(str(type_found.max), type_found),
                            type_found,
                        )
                    self._result.append(op)
                    set_val(expression, val)
                    return

        # This does not support solidity 0.4 contract_name.balance
        if (isinstance(expr, Variable)
                and expr.type == ElementaryType("address")
                and expression.member_name in ["balance", "code", "codehash"]):
            val = TemporaryVariable(self._node)
            name = expression.member_name + "(address)"
            sol_func = SolidityFunction(name)
            s = SolidityCall(
                sol_func,
                1,
                val,
                sol_func.return_type,
            )
            s.set_expression(expression)
            s.arguments.append(expr)
            self._result.append(s)
            set_val(expression, val)
            return

        if isinstance(expr, TypeAlias) and expression.member_name in [
                "wrap", "unwrap"
        ]:
            # The logic is be handled by _post_call_expression
            set_val(expression, expr)
            return

        # Early lookup to detect user defined types from other contracts definitions
        # contract A { type MyInt is int}
        # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}}
        # The logic is handled by _post_call_expression
        if isinstance(expr, Contract):
            if expression.member_name in expr.file_scope.user_defined_types:
                set_val(
                    expression,
                    expr.file_scope.user_defined_types[expression.member_name])
                return

        val = ReferenceVariable(self._node)
        member = Member(expr, Constant(expression.member_name), val)
        member.set_expression(expression)
        self._result.append(member)
        set_val(expression, val)
Exemple #16
0
 def _post_literal(self, expression):
     cst = Constant(expression.value, expression.type)
     set_val(expression, cst)
Exemple #17
0
def propagate_types(ir, node):
    # propagate the type
    using_for = node.function.contract.using_for
    if isinstance(ir, OperationWithLValue):
        # Force assignment in case of missing previous correct type
        if not ir.lvalue.type:
            if isinstance(ir, Assignment):
                ir.lvalue.set_type(ir.rvalue.type)
            elif isinstance(ir, Binary):
                if BinaryType.return_bool(ir.type):
                    ir.lvalue.set_type(ElementaryType('bool'))
                else:
                    ir.lvalue.set_type(ir.variable_left.type)
            elif isinstance(ir, Delete):
                # nothing to propagate
                pass
            elif isinstance(ir, LibraryCall):
                return convert_type_library_call(ir, ir.destination)
            elif isinstance(ir, HighLevelCall):
                t = ir.destination.type

                # Temporary operation (they are removed later)
                if t is None:
                    return

                if isinstance(t, ElementaryType) and t.name == 'address':
                    if can_be_solidity_func(ir):
                        return convert_to_solidity_func(ir)

                # convert library
                if t in using_for or '*' in using_for:
                    new_ir = convert_to_library(ir, node, using_for)
                    if new_ir:
                        return new_ir

                if isinstance(t, UserDefinedType):
                    # UserdefinedType
                    t_type = t.type
                    if isinstance(t_type, Contract):
                        contract = node.slither.get_contract_from_name(t_type.name)
                        return convert_type_of_high_and_internal_level_call(ir, contract)

                # Convert HighLevelCall to LowLevelCall
                if isinstance(t, ElementaryType) and t.name == 'address':
                    if ir.destination.name == 'this':
                        return convert_type_of_high_and_internal_level_call(ir, node.function.contract)
                    if can_be_low_level(ir):
                        return convert_to_low_level(ir)

                # Convert push operations
                # May need to insert a new operation
                # Which leads to return a list of operation
                if isinstance(t, ArrayType) or (isinstance(t, ElementaryType) and t.type == 'bytes'):
                    if ir.function_name == 'push' and len(ir.arguments) == 1:
                        return convert_to_push(ir, node)
                    if ir.function_name == 'pop' and len(ir.arguments) == 0:
                        return convert_to_pop(ir, node)

            elif isinstance(ir, Index):
                if isinstance(ir.variable_left.type, MappingType):
                    ir.lvalue.set_type(ir.variable_left.type.type_to)
                elif isinstance(ir.variable_left.type, ArrayType):
                    ir.lvalue.set_type(ir.variable_left.type.type)

            elif isinstance(ir, InitArray):
                length = len(ir.init_values)
                t = ir.init_values[0].type
                ir.lvalue.set_type(ArrayType(t, length))
            elif isinstance(ir, InternalCall):
                # if its not a tuple, return a singleton
                if ir.function is None:
                    convert_type_of_high_and_internal_level_call(ir, node.function.contract)
                return_type = ir.function.return_type
                if return_type:
                    if len(return_type) == 1:
                        ir.lvalue.set_type(return_type[0])
                    elif len(return_type) > 1:
                        ir.lvalue.set_type(return_type)
                else:
                    ir.lvalue = None
            elif isinstance(ir, InternalDynamicCall):
                # if its not a tuple, return a singleton
                return_type = ir.function_type.return_type
                if return_type:
                    if len(return_type) == 1:
                        ir.lvalue.set_type(return_type[0])
                    else:
                        ir.lvalue.set_type(return_type)
                else:
                    ir.lvalue = None
            elif isinstance(ir, LowLevelCall):
                # Call are not yet converted
                # This should not happen
                assert False
            elif isinstance(ir, Member):
                # 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
                    length.set_node(ir.node)
                    return length
                if ir.variable_right == 'balance' and not isinstance(ir.variable_left, Contract) and isinstance(
                        ir.variable_left.type, ElementaryType):
                    b = Balance(ir.variable_left, ir.lvalue)
                    b.set_expression(ir.expression)
                    b.set_node(ir.node)
                    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.set_node(ir.node)
                    assignment.lvalue.set_type(ElementaryType('bytes4'))
                    return assignment
                if isinstance(ir.variable_left, TemporaryVariable) and isinstance(ir.variable_left.type,
                                                                                  TypeInformation):
                    return _convert_type_contract(ir, node.function.slither)
                left = ir.variable_left
                t = None
                if isinstance(left, (Variable, SolidityVariable)):
                    t = ir.variable_left.type
                elif isinstance(left, (Contract, Enum, Structure)):
                    t = UserDefinedType(left)
                # can be None due to temporary operation
                if t:
                    if isinstance(t, UserDefinedType):
                        # UserdefinedType
                        type_t = t.type
                        if isinstance(type_t, Enum):
                            ir.lvalue.set_type(t)
                        elif isinstance(type_t, Structure):
                            elems = type_t.elems
                            for elem in elems:
                                if elem == ir.variable_right:
                                    ir.lvalue.set_type(elems[elem].type)
                        else:
                            assert isinstance(type_t, Contract)
                            # Allow type propagtion as a Function
                            # Only for reference variables
                            # This allows to track the selector keyword
                            # We dont need to check for function collision, as solc prevents the use of selector
                            # if there are multiple functions with the same name
                            f = next((f for f in type_t.functions if f.name == ir.variable_right), None)
                            if f:
                                ir.lvalue.set_type(f)
                            else:
                                # Allow propgation for variable access through contract's nale
                                # like Base_contract.my_variable
                                v = next((v for v in type_t.state_variables if v.name == ir.variable_right), None)
                                if v:
                                    ir.lvalue.set_type(v.type)
            elif isinstance(ir, NewArray):
                ir.lvalue.set_type(ir.array_type)
            elif isinstance(ir, NewContract):
                contract = node.slither.get_contract_from_name(ir.contract_name)
                ir.lvalue.set_type(UserDefinedType(contract))
            elif isinstance(ir, NewElementaryType):
                ir.lvalue.set_type(ir.type)
            elif isinstance(ir, NewStructure):
                ir.lvalue.set_type(UserDefinedType(ir.structure))
            elif isinstance(ir, Push):
                # No change required
                pass
            elif isinstance(ir, Send):
                ir.lvalue.set_type(ElementaryType('bool'))
            elif isinstance(ir, SolidityCall):
                if ir.function.name == 'type(address)':
                    ir.function.return_type = [TypeInformation(ir.arguments[0])]
                return_type = ir.function.return_type
                if len(return_type) == 1:
                    ir.lvalue.set_type(return_type[0])
                elif len(return_type) > 1:
                    ir.lvalue.set_type(return_type)
            elif isinstance(ir, TypeConversion):
                ir.lvalue.set_type(ir.type)
            elif isinstance(ir, Unary):
                ir.lvalue.set_type(ir.rvalue.type)
            elif isinstance(ir, Unpack):
                types = ir.tuple.type.type
                idx = ir.index
                t = types[idx]
                ir.lvalue.set_type(t)
            elif isinstance(ir,
                            (Argument, TmpCall, TmpNewArray, TmpNewContract, TmpNewStructure, TmpNewElementaryType)):
                # temporary operation; they will be removed
                pass
            else:
                raise SlithIRError('Not handling {} during type propgation'.format(type(ir)))