diff --git a/NEWS b/NEWS index d2537c4f92b..d7da084b1ea 100644 --- a/NEWS +++ b/NEWS @@ -49,6 +49,7 @@ PHP NEWS - Fixed bug #42069 (parse_ini_file() allows using some non-alpha numeric characters). (Jani) - Fixed bug #37911 (preg_replace_callback() ignores named groups). (Nuno) +- Fixed bug #35163 (Array elements can lose references). (Dmitry) - Fixed bug #27372 (parse error loading browscap.ini at apache startup). (Jani) diff --git a/Zend/tests/bug35163.phpt b/Zend/tests/bug35163.phpt new file mode 100755 index 00000000000..4501fa9372c --- /dev/null +++ b/Zend/tests/bug35163.phpt @@ -0,0 +1,38 @@ +--TEST-- +Bug #35163 (Array elements can lose references) +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + &array(3) { + [0]=> + int(2) + [1]=> + &array(3) { + [0]=> + int(2) + [1]=> + *RECURSION* + [2]=> + *RECURSION* + } + [2]=> + &array(3) { + [0]=> + int(2) + [1]=> + *RECURSION* + [2]=> + *RECURSION* + } + } +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 636a9c29ee0..e2a3621d139 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -927,6 +927,9 @@ void zend_do_end_variable_parse(int type, int arg_offset TSRMLS_DC) if (le == NULL) break; opline_ptr = (zend_op *)le->data; } + if (opline->opcode == ZEND_FETCH_DIM_W) { + opline->extended_value = arg_offset; + } } zend_llist_destroy(fetch_list_ptr); zend_stack_del_top(&CG(bp_stack)); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 73fc0551629..7bab0f323d5 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -567,7 +567,7 @@ non_empty_for_expr: expr_without_variable: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } - | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } + | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } | variable '=' '&' T_NEW class_name_reference { zend_error(E_STRICT, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 54af310f5a9..7e1a41bbb66 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1066,6 +1066,14 @@ ZEND_VM_HANDLER(84, ZEND_FETCH_DIM_W, VAR|CV, CONST|TMP|VAR|UNUSED|CV) AI_USE_PTR(EX_T(opline->result.u.var).var); } FREE_OP1_VAR_PTR(); + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5cd25157e6e..7a9a99fcdfa 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -9219,6 +9219,14 @@ static int ZEND_FETCH_DIM_W_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -10862,6 +10870,14 @@ static int ZEND_FETCH_DIM_W_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -12441,6 +12457,14 @@ static int ZEND_FETCH_DIM_W_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -13623,6 +13647,14 @@ static int ZEND_FETCH_DIM_W_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -14581,6 +14613,14 @@ static int ZEND_FETCH_DIM_W_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } if (free_op1.var) {zval_ptr_dtor(&free_op1.var);}; + + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -21692,6 +21732,13 @@ static int ZEND_FETCH_DIM_W_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -23171,6 +23218,13 @@ static int ZEND_FETCH_DIM_W_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -24653,6 +24707,13 @@ static int ZEND_FETCH_DIM_W_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -25737,6 +25798,13 @@ static int ZEND_FETCH_DIM_W_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); } @@ -26605,6 +26673,13 @@ static int ZEND_FETCH_DIM_W_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) AI_USE_PTR(EX_T(opline->result.u.var).var); } + /* We are going to assign the result by reference */ + if (opline->extended_value) { + Z_DELREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + SEPARATE_ZVAL_TO_MAKE_IS_REF(EX_T(opline->result.u.var).var.ptr_ptr); + Z_ADDREF_PP(EX_T(opline->result.u.var).var.ptr_ptr); + } + ZEND_VM_NEXT_OPCODE(); }