Example #1
0
def parse_yul_identifier(root: YulScope, _node: YulNode, ast: Dict) -> Optional[Expression]:
    name = ast["name"]

    if name in builtins:
        return Identifier(YulBuiltin(name))

    # check function-scoped variables
    parent_func = root.parent_func
    if parent_func:
        variable = parent_func.get_local_variable_from_name(name)
        if variable:
            return Identifier(variable)

        if isinstance(parent_func, FunctionContract):
            variable = parent_func.contract.get_state_variable_from_name(name)
            if variable:
                return Identifier(variable)

    # check yul-scoped variable
    variable = root.get_yul_local_variable_from_name(name)
    if variable:
        return Identifier(variable.underlying)

    # check yul-scoped function

    func = root.get_yul_local_function_from_name(name)
    if func:
        return Identifier(func.underlying)

    magic_suffix = _parse_yul_magic_suffixes(name, root)
    if magic_suffix:
        return magic_suffix

    raise SlitherException(f"unresolved reference to identifier {name}")
Example #2
0
def parse_yul_typed_name(root: YulScope, _node: YulNode,
                         ast: Dict) -> Optional[Expression]:
    var = root.get_yul_local_variable_from_name(ast["name"])

    i = Identifier(var.underlying)
    i.type = var.underlying.type
    return i
Example #3
0
def _parse_yul_magic_suffixes(name: str, root: YulScope) -> Optional[Expression]:
    # check for magic suffixes
    # TODO: the following leads to wrong IR
    # Currently SlithIR doesnt support raw access to memory
    # So things like .offset/.slot will return the variable
    # Instaed of the actual offset/slot
    if name.endswith(("_slot", ".slot")):
        potential_name = name[:-5]
        variable_found = _check_for_state_variable_name(root, potential_name)
        if variable_found:
            return variable_found
        var = root.function.get_local_variable_from_name(potential_name)
        if var and var.is_storage:
            return Identifier(var)
    if name.endswith(("_offset", ".offset")):
        potential_name = name[:-7]
        variable_found = _check_for_state_variable_name(root, potential_name)
        if variable_found:
            return variable_found
        var = root.function.get_local_variable_from_name(potential_name)
        if var and var.location == "calldata":
            return Identifier(var)
    if name.endswith(".length"):
        # TODO: length should create a new IP operation LENGTH var
        # The code below is an hotfix to allow slither to process length in yul
        # Until we have a better support
        potential_name = name[:-7]
        var = root.function.get_local_variable_from_name(potential_name)
        if var and var.location == "calldata":
            return Identifier(var)
    return None
Example #4
0
def parse_yul_function_call(root: YulScope, node: YulNode,
                            ast: Dict) -> Optional[Expression]:
    args = [parse_yul(root, node, arg) for arg in ast["arguments"]]
    ident = parse_yul(root, node, ast["functionName"])

    if not isinstance(ident, Identifier):
        raise SlitherException(
            "expected identifier from parsing function name")

    if isinstance(ident.value, YulBuiltin):
        name = ident.value.name
        if name in binary_ops:
            if name in ["shl", "shr", "sar"]:
                # lmao ok
                return BinaryOperation(args[1], args[0], binary_ops[name])

            return BinaryOperation(args[0], args[1], binary_ops[name])

        if name in unary_ops:
            return UnaryOperation(args[0], unary_ops[name])

        ident = Identifier(
            SolidityFunction(format_function_descriptor(ident.value.name)))

    if isinstance(ident.value, Function):
        return CallExpression(ident, args,
                              vars_to_typestr(ident.value.returns))
    if isinstance(ident.value, SolidityFunction):
        return CallExpression(ident, args,
                              vars_to_typestr(ident.value.return_type))

    raise SlitherException(
        f"unexpected function call target type {str(type(ident.value))}")
Example #5
0
    def _create_node(
        self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
    ):
        from slither.core.cfg.node import Node, NodeType
        from slither.core.expressions import (
            AssignmentOperationType,
            AssignmentOperation,
            Identifier,
        )

        # Function uses to create node for state variable declaration statements
        node = Node(NodeType.OTHER_ENTRYPOINT, counter, scope)
        node.set_offset(variable.source_mapping, self.compilation_unit)
        node.set_function(func)
        func.add_node(node)
        assert variable.expression
        expression = AssignmentOperation(
            Identifier(variable),
            variable.expression,
            AssignmentOperationType.ASSIGN,
            variable.type,
        )

        expression.set_offset(variable.source_mapping, self.compilation_unit)
        node.add_expression(expression)
        return node
Example #6
0
def _check_for_state_variable_name(root: YulScope, potential_name: str) -> Optional[Identifier]:
    root_function = root.function
    if isinstance(root_function, FunctionContract):
        var = root_function.contract.get_state_variable_from_name(potential_name)
        if var:
            return Identifier(var)
    return None
    def _stat_vars_info_in_contract(self):

        # 全局变量定义
        for v in self.contract.state_variables:
            if v.expression is None:
                exp = str(v.type) + " " + str(Identifier(v))
                self.state_var_declare_function_map[str(Identifier(v))] = {
                    "type": str(v.type),
                    "exp": exp
                }

        for function in self.contract.functions:

            # print("[列表] 函数名:{}  fid:{}".format(function.name, function.id))
            self.fid_2_function[function.id] = function

            # 全局变量定义
            if function.is_constructor or function.is_constructor_variables:
                for node in function.nodes:
                    for v in node.state_variables_written:
                        full_exp = "{} {}".format(str(v.type), node.expression)
                        self.state_var_declare_function_map[str(v)] = {
                            "fun": function,
                            "expr": node.expression,
                            "full_expr": full_exp
                        }

            else:
                # 全局变量读
                for v in function.state_variables_read:
                    if str(v) not in self.state_var_read_function_map:
                        self.state_var_read_function_map[str(v)] = [function]
                    else:
                        self.state_var_read_function_map[str(v)].append(
                            function)

                # 全局变量写
                for v in function.state_variables_written:

                    if not function.can_send_eth():
                        continue  # NOTE:对于参与交易的函数,下面会进行重点分析

                    if str(v) not in self.state_var_write_function_map:
                        self.state_var_write_function_map[str(v)] = [function]
                    else:
                        self.state_var_write_function_map[str(v)].append(
                            function)
Example #8
0
    def _create_node(self, func, counter, variable):
        # Function uses to create node for state variable declaration statements
        node = Node(NodeType.OTHER_ENTRYPOINT, counter)
        node.set_offset(variable.source_mapping, self.slither)
        node.set_function(func)
        func.add_node(node)
        expression = AssignmentOperation(Identifier(variable),
                                         variable.expression,
                                         AssignmentOperationType.ASSIGN,
                                         variable.type)

        node.add_expression(expression)
        return node
Example #9
0
def parse_yul_identifier(root: YulScope, _node: YulNode,
                         ast: Dict) -> Optional[Expression]:
    name = ast["name"]

    if name in builtins:
        return Identifier(YulBuiltin(name))

    # check function-scoped variables
    if root.parent_func:
        variable = root.parent_func.get_local_variable_from_name(name)
        if variable:
            return Identifier(variable)

        variable = root.parent_func.contract.get_state_variable_from_name(name)
        if variable:
            return Identifier(variable)

    # check yul-scoped variable
    variable = root.get_yul_local_variable_from_name(name)
    if variable:
        return Identifier(variable.underlying)

    # check yul-scoped function

    func = root.get_yul_local_function_from_name(name)
    if func:
        return Identifier(func.underlying)

    # check for magic suffixes
    if name.endswith("_slot"):
        potential_name = name[:-5]
        var = root.function.contract.get_state_variable_from_name(
            potential_name)
        if var:
            return Identifier(var)
        var = root.function.get_local_variable_from_name(potential_name)
        if var and var.is_storage:
            return Identifier(var)
    if name.endswith("_offset"):
        potential_name = name[:-7]
        var = root.function.contract.get_state_variable_from_name(
            potential_name)
        if var:
            return Identifier(var)

    raise SlitherException(f"unresolved reference to identifier {name}")
Example #10
0
    def analyze_expressions(self):
        if self._node.type == NodeType.VARIABLE and not self._node.expression:
            self._node.add_expression(
                self._node.variable_declaration.expression)
        if self._unparsed_expression:
            expression = parse_yul(self._scope, self,
                                   self._unparsed_expression)
            self._node.add_expression(expression)

        if self._node.expression:
            if self._node.type == NodeType.VARIABLE:
                # Update the expression to be an assignement to the variable
                _expression = AssignmentOperation(
                    Identifier(self._node.variable_declaration),
                    self._node.expression,
                    AssignmentOperationType.ASSIGN,
                    self._node.variable_declaration.type,
                )
                _expression.set_offset(self._node.expression.source_mapping,
                                       self._node.slither)
                self._node.add_expression(_expression, bypass_verif_empty=True)

            expression = self._node.expression
            read_var = ReadVar(expression)
            self._node.variables_read_as_expression = read_var.result()

            write_var = WriteVar(expression)
            self._node.variables_written_as_expression = write_var.result()

            find_call = FindCalls(expression)
            self._node.calls_as_expression = find_call.result()
            self._node.external_calls_as_expressions = [
                c for c in self._node.calls_as_expression
                if not isinstance(c.called, Identifier)
            ]
            self._node.internal_calls_as_expressions = [
                c for c in self._node.calls_as_expression
                if isinstance(c.called, Identifier)
            ]
Example #11
0
    for contract in slither.contracts:

        state_var_declare_function_map = {}  # 全局变量定义函数
        state_var_write_function_map = {}  # 全局变量写函数列表
        state_var_read_function_map = {}  # 全局变量读函数列表
        transaction_state_vars = []  # 与交易行为相关的全局变量
        transaction_state_vars_stmts = {}
        eth_send_functions = {}
        functions_slice_criterias = {}  # 每个函数对应的切片准则:阶段1、4都会生成切片准则

        # NOTE: stat_var <==> function 对应表
        print("\n=====阶段1:stat_var <==> function 对应表=====\n")

        for v in contract.state_variables:
            if v.expression is None:
                exp = str(v.type) + " " + str(Identifier(v))
                print("expression:", exp)
                state_var_declare_function_map[str(Identifier(v))] = {
                    "exp": exp
                }

        for function in contract.functions:

            get_function_cfg(function)

            # 全局变量定义
            if function.is_constructor or function.is_constructor_variables:
                for v in function.state_variables_written:
                    if str(v) not in state_var_declare_function_map:
                        state_var_declare_function_map[str(v)] = {
                            "fun": function