# Buggy code
def array_back(
    param, nodes, vul_function=None, file_path=None, isback=None
):  # 回溯数组定义赋值
    """
    递归回溯数组赋值定义
    :param isback:
    :param file_path:
    :param vul_function:
    :param param:
    :param nodes:
    :return:
    """
    param_name = param.node.name
    param_expr = param.expr

    is_co = 3
    cp = param
    expr_lineno = 0

    # print nodes
    for node in nodes[::-1]:
        if isinstance(node, php.Assignment):
            param_node_name = get_node_name(node.node)
            param_node = node.node
            param_node_expr = node.expr

            if param_node_name == param_name:  # 处理数组中值被改变的问题
                if isinstance(node.expr, php.Array):
                    for p_node in node.expr.nodes:
                        if p_node.key == param_expr:
                            if isinstance(
                                p_node.value, php.ArrayOffset
                            ):  # 如果赋值值仍然是数组，先经过判断在进入递归
                                is_co, cp = is_controllable(p_node.value.node.name)

                                if is_co != 1:
                                    is_co, cp, expr_lineno = array_back(
                                        param, nodes, file_path=file_path, isback=isback
                                    )

                            else:
                                n_node = php.Variable(p_node.value)
                                is_co, cp, expr_lineno = parameters_back(
                                    n_node,
                                    nodes,
                                    vul_function=vul_function,
                                    file_path=file_path,
                                    isback=isback,
                                )

            if param == param_node:  # 处理数组一次性赋值，左值为数组
                if isinstance(
                    param_node_expr, php.ArrayOffset
                ):  # 如果赋值值仍然是数组，先经过判断在进入递归
                    is_co, cp = is_controllable(param_node_expr.node.name)

                    if is_co != 1:
                        is_co, cp, expr_lineno = array_back(
                            param, nodes, file_path=file_path, isback=isback
                        )
                else:
                    is_co, cp = is_controllable(param_node_expr)

                    if is_co != 1 and is_co != -1:
                        n_node = php.Variable(param_node_expr.node.value)
                        is_co, cp, expr_lineno = parameters_back(
                            n_node,
                            nodes,
                            vul_function=vul_function,
                            file_path=file_path,
                            isback=isback,
                        )

    return is_co, cp, expr_lineno


# Traceback (AttributeError)
[DEBUG] [MainThread] [18:13:28] [engine.py:801] [RULE_MATCH] ['mysql_query', 'mysql_db_query']
[DEBUG] [MainThread] [18:13:28] [parser.py:1316] [AST] vul_function:mysql_query
[DEBUG] [MainThread] [18:13:28] [parser.py:1123] [AST] AST to find param Variable('$c')
[DEBUG] [MainThread] [18:13:28] [parser.py:598] [BT] param=Variable('$c'),nodes=[Function('random', [FormalParameter('$val', None, False, None)], [Assignment(Variable('$b'), ArrayOffset(Variable('$_GET'), 'maple'), False), Assignment(Variable('$c'), ArrayOffset(Variable('$b'), 0), False), FunctionCall('mysql_query', [Parameter(Variable('$c'), False)])], False)],function_params=None, lineno=6,function_flag=0,vul_function=mysql_query,file_path=/root/cobra/tests/vulnerabilities/sql.php,isback=False,parent_node=0
[DEBUG] [MainThread] [18:13:28] [parser.py:793] [AST] param $c line 6 in function random line 3, start ast in function
[DEBUG] [MainThread] [18:13:28] [parser.py:598] [BT] param=Variable('$c'),nodes=[Assignment(Variable('$b'), ArrayOffset(Variable('$_GET'), 'maple'), False), Assignment(Variable('$c'), ArrayOffset(Variable('$b'), 0), False)],function_params=[FormalParameter('$val', None, False, None)], lineno=3,function_flag=1,vul_function=mysql_query,file_path=/root/cobra/tests/vulnerabilities/sql.php,isback=False,parent_node=None
[DEBUG] [MainThread] [18:13:28] [parser.py:641] [AST] Find $c=$b in line 5, start ast for param $b
[DEBUG] [MainThread] [18:13:28] [parser.py:598] [BT] param=ArrayOffset(Variable('$b'), 0),nodes=[Assignment(Variable('$b'), ArrayOffset(Variable('$_GET'), 'maple'), False)],function_params=[FormalParameter('$val', None, False, None)], lineno=3,function_flag=1,vul_function=mysql_query,file_path=/root/cobra/tests/vulnerabilities/sql.php,isback=False,parent_node=0
[DEBUG] [MainThread] [18:13:28] [parser.py:615] [AST] AST analysis for ArrayOffset  in line 5
[DEBUG] [MainThread] [18:13:28] [parser.py:1169] Traceback (most recent call last):
File "/root/Cobra-W/cobra/core_engine/php/parser.py", line 1155, in anlysis_function
file_path=file_path)
File "/root/Cobra-W/cobra/core_engine/php/parser.py", line 1322, in analysis_variable_node
is_co, cp, expr_lineno, chain = anlysis_params(param, file_path, param_lineno, vul_function=vul_function)
File "/root/Cobra-W/cobra/core_engine/php/parser.py", line 1133, in anlysis_params
vul_function=vul_function)
File "/root/Cobra-W/cobra/core_engine/php/parser.py", line 967, in deep_parameters_back
file_path=file_path, isback=isback, parent_node=0)
File "/root/Cobra-W/cobra/core_engine/php/parser.py", line 812, in parameters_back
if node_param.name == cp.name:
AttributeError: 'ArrayOffset' object has no attribute 'name'

[DEBUG] [MainThread] [18:13:28] [engine.py:809] [AST] [RET] []

# Fixed code
def array_back(
    param, nodes, vul_function=None, file_path=None, isback=None
):  # 回溯数组定义赋值
    """
    递归回溯数组赋值定义
    :param isback:
    :param file_path:
    :param vul_function:
    :param param:
    :param nodes:
    :return:
    """
    param_name = param.node.name
    param_expr = param.expr

    is_co = 3
    cp = param
    expr_lineno = param.lineno

    for node in nodes[::-1]:
        if isinstance(node, php.Assignment):
            param_node_name = get_node_name(node.node)
            param_node = node.node
            param_node_expr = node.expr

            if (
                param_node_name == param_name or param == param_node
            ):  # 处理数组中值被改变的问题
                if isinstance(param_node_expr, php.Array):
                    for p_node in node.expr.nodes:
                        if p_node.key == param_expr:
                            if isinstance(
                                p_node.value, php.ArrayOffset
                            ):  # 如果赋值值仍然是数组，先经过判断在进入递归
                                is_co, cp = is_controllable(p_node.value.node.name)

                                if is_co != 1:
                                    is_co, cp, expr_lineno = array_back(
                                        param, nodes, file_path=file_path, isback=isback
                                    )

                            else:
                                n_node = php.Variable(p_node.value)
                                is_co, cp, expr_lineno = parameters_back(
                                    n_node,
                                    nodes,
                                    vul_function=vul_function,
                                    file_path=file_path,
                                    isback=isback,
                                )

                # if param == param_node:  # 处理数组一次性赋值，左值为数组
                if isinstance(
                    param_node_expr, php.ArrayOffset
                ):  # 如果赋值值仍然是数组，先经过判断在进入递归
                    is_co, cp = is_controllable(param_node_expr.node.name)

                    if is_co != 1:
                        is_co, cp, expr_lineno = array_back(
                            param, nodes, file_path=file_path, isback=isback
                        )
                else:
                    is_co, cp = is_controllable(param_node_expr)

                    if is_co != 1 and is_co != -1:
                        n_node = php.Variable(param_node_expr.node.value)
                        is_co, cp, expr_lineno = parameters_back(
                            n_node,
                            nodes,
                            vul_function=vul_function,
                            file_path=file_path,
                            isback=isback,
                        )

    return is_co, cp, expr_lineno