diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9b79202014d..de17463058f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2713,19 +2713,42 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n { zend_ast_list *list = zend_ast_get_list(ast); uint32_t i; + zend_ulong next_index = 0; zend_bool has_elems = 0; for (i = 0; i < list->children; ++i) { - zend_ast *var_ast = list->child[i]; + zend_ast *pair_ast = list->child[i]; + zend_ast *var_ast; + zend_ast *key_ast; znode fetch_result, dim_node; - if (var_ast == NULL) { + if (pair_ast == NULL) { + next_index++; continue; } - has_elems = 1; - dim_node.op_type = IS_CONST; - ZVAL_LONG(&dim_node.u.constant, i); + var_ast = pair_ast->child[0]; + key_ast = pair_ast->child[1]; + + if (key_ast) { + zend_compile_expr(&dim_node, key_ast); + zend_handle_numeric_op(&dim_node); + + if (Z_TYPE(dim_node.u.constant) != IS_LONG && Z_TYPE(dim_node.u.constant) != IS_STRING) { + zend_error_noreturn(E_COMPILE_ERROR, "Key must be an integer or string literal"); + } + + if (Z_TYPE(dim_node.u.constant) == IS_LONG) { + next_index = Z_LVAL(dim_node.u.constant); + } + } else { + dim_node.op_type = IS_CONST; + ZVAL_LONG(&dim_node.u.constant, next_index); + + next_index++; + } + + has_elems = 1; if (expr_node->op_type == IS_CONST) { Z_TRY_ADDREF(expr_node->u.constant); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 754c50215da..2f64ae55f24 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1177,8 +1177,12 @@ assignment_list: ; assignment_list_element: - variable { $$ = $1; } + variable { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $1, NULL); } + | scalar T_DOUBLE_ARROW variable + { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $3, $1); } | T_LIST '(' assignment_list ')' { $$ = $3; } + | scalar T_DOUBLE_ARROW T_LIST '(' assignment_list ')' + { $$ = zend_ast_create(ZEND_AST_ARRAY_ELEM, $5, $1); } | /* empty */ { $$ = NULL; } ; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index af9daa89b1d..98e477e8c44 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2073,13 +2073,26 @@ ZEND_VM_HANDLER(98, ZEND_FETCH_LIST, CONST|TMPVAR|CV, CONST) ZEND_VM_C_LABEL(try_fetch_list): if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; + + if (Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_LONG) { + value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_hash_find(Z_ARRVAL_P(container), Z_STR_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } } else if (OP1_TYPE != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a4edfd0f98e..9a0bf762fc3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5753,13 +5753,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CONST_CONST_HA try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_LONG) { + value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_hash_find(Z_ARRVAL_P(container), Z_STR_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } } else if (IS_CONST != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && @@ -37866,13 +37879,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_CV_CONST_HANDL try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_LONG) { + value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_hash_find(Z_ARRVAL_P(container), Z_STR_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } } else if (IS_CV != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) && @@ -51017,13 +51043,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_LIST_SPEC_TMPVAR_CONST_H try_fetch_list: if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - zval *value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + zval *value; - if (UNEXPECTED(value == NULL)) { - zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); - ZVAL_NULL(EX_VAR(opline->result.var)); + if (Z_TYPE_P(EX_CONSTANT(opline->op2)) == IS_LONG) { + value = zend_hash_index_find(Z_ARRVAL_P(container), Z_LVAL_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE,"Undefined offset: " ZEND_ULONG_FMT, Z_LVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } else { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_hash_find(Z_ARRVAL_P(container), Z_STR_P(EX_CONSTANT(opline->op2))); + + if (UNEXPECTED(value == NULL)) { + zend_error(E_NOTICE, "Undefined index: %s", Z_STRVAL_P(EX_CONSTANT(opline->op2))); + ZVAL_NULL(EX_VAR(opline->result.var)); + } else { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } } } else if ((IS_TMP_VAR|IS_VAR) != IS_CONST && UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT) &&