From: Dmitry Stogov Date: Thu, 24 Jul 2008 11:47:51 +0000 (+0000) Subject: Fixed bug #45178 (memory corruption on assignment result of "new" by reference) X-Git-Tag: php-5.3.0alpha1~161 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=44325e647302aa29e5ad3a2a324a57ed928d8f72;p=php Fixed bug #45178 (memory corruption on assignment result of "new" by reference) --- diff --git a/Zend/tests/bug45178.phpt b/Zend/tests/bug45178.phpt new file mode 100755 index 0000000000..5ce1859948 --- /dev/null +++ b/Zend/tests/bug45178.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #45178 memory corruption on assignment result of "new" by reference +--FILE-- +error = array($this,$this); + } +} +$a =& new Foo(); + +class Bar { + function __construct() { + $this->_rme2 = $this; + } +} + +$b =& new Bar(); +$b->_rme2 = 0; +var_dump($b); +?> +--EXPECTF-- +Deprecated: Assigning the return value of new by reference is deprecated in %sbug45178.php on line 7 + +Deprecated: Assigning the return value of new by reference is deprecated in %sbug45178.php on line 15 +object(Bar)#%d (1) { + ["_rme2"]=> + int(0) +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f709132544..79c9afe185 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -683,6 +683,8 @@ void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar TSRMLS_DC) opline->opcode = ZEND_ASSIGN_REF; if (zend_is_function_or_method_call(rvar)) { opline->extended_value = ZEND_RETURNS_FUNCTION; + } else if (rvar->u.EA.type & ZEND_PARSED_NEW) { + opline->extended_value = ZEND_RETURNS_NEW; } else { opline->extended_value = 0; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 89ae65108c..7ddbe50f56 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -645,6 +645,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_PARSED_FUNCTION_CALL (1<<3) #define ZEND_PARSED_VARIABLE (1<<4) #define ZEND_PARSED_REFERENCE_VARIABLE (1<<5) +#define ZEND_PARSED_NEW (1<<6) /* unset types */ @@ -725,6 +726,7 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_RETURNS_FUNCTION 1<<0 +#define ZEND_RETURNS_NEW 1<<1 END_EXTERN_C() diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 23de160976..197f09ddaa 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -576,7 +576,7 @@ 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_assign(&$$, &$1, &$3 TSRMLS_CC); } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } - | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "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(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } + | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "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(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.u.EA.type = ZEND_PARSED_NEW; 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); } | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 806a823ae6..a63f11d134 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1624,6 +1624,8 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) } zend_error(E_STRICT, "Only variables should be assigned by reference"); ZEND_VM_DISPATCH_TO_HANDLER(ZEND_ASSIGN); + } else if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + PZVAL_LOCK(*value_ptr_ptr); } if (OP1_TYPE == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); @@ -1636,6 +1638,10 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV) } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); + if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + Z_DELREF_PP(variable_ptr_ptr); + } + if (!RETURN_VALUE_UNUSED(&opline->result)) { AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); PZVAL_LOCK(*variable_ptr_ptr); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 83286092c8..3014b9ca2c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -13825,6 +13825,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL } zend_error(E_STRICT, "Only variables should be assigned by reference"); return ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + PZVAL_LOCK(*value_ptr_ptr); } if (IS_VAR == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); @@ -13837,6 +13839,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); + if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + Z_DELREF_PP(variable_ptr_ptr); + } + if (!RETURN_VALUE_UNUSED(&opline->result)) { AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); PZVAL_LOCK(*variable_ptr_ptr); @@ -16245,6 +16251,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE } zend_error(E_STRICT, "Only variables should be assigned by reference"); return ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + PZVAL_LOCK(*value_ptr_ptr); } if (IS_VAR == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); @@ -16257,6 +16265,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); + if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + Z_DELREF_PP(variable_ptr_ptr); + } + if (!RETURN_VALUE_UNUSED(&opline->result)) { AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); PZVAL_LOCK(*variable_ptr_ptr); @@ -27120,6 +27132,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE } zend_error(E_STRICT, "Only variables should be assigned by reference"); return ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + PZVAL_LOCK(*value_ptr_ptr); } if (IS_CV == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); @@ -27132,6 +27146,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); + if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + Z_DELREF_PP(variable_ptr_ptr); + } + if (!RETURN_VALUE_UNUSED(&opline->result)) { AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); PZVAL_LOCK(*variable_ptr_ptr); @@ -29317,6 +29335,8 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER } zend_error(E_STRICT, "Only variables should be assigned by reference"); return ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + PZVAL_LOCK(*value_ptr_ptr); } if (IS_CV == IS_VAR && EX_T(opline->op1.u.var).var.ptr_ptr == &EX_T(opline->op1.u.var).var.ptr) { zend_error(E_ERROR, "Cannot assign by reference to overloaded object"); @@ -29329,6 +29349,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER } zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC); + if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) { + Z_DELREF_PP(variable_ptr_ptr); + } + if (!RETURN_VALUE_UNUSED(&opline->result)) { AI_SET_PTR(EX_T(opline->result.u.var).var, *variable_ptr_ptr); PZVAL_LOCK(*variable_ptr_ptr);