Skip to content

Commit

Permalink
Fixed bug #45178 (memory corruption on assignment result of "new" by …
Browse files Browse the repository at this point in the history
…reference)
  • Loading branch information
dstogov committed Jul 24, 2008
1 parent ec1e964 commit d2f478a
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 1 deletion.
2 changes: 2 additions & 0 deletions NEWS
Expand Up @@ -33,6 +33,8 @@ PHP NEWS
- Fixed bug #45251 (double free or corruption with setAttributeNode()). (Rob)
- Fixed bug #45220 (curl_read callback returns -1 when needs to return
size_t (unsigned)). (Felipe)
- Fixed bug #45178 (memory corruption on assignment result of "new" by
reference). (Dmitry)
- Fixed bug #45151 (Crash with URI/file..php (filename contains 2 dots)).
(Dmitry)
- Fixed bug #45139 (ReflectionProperty returns incorrect declaring class).
Expand Down
29 changes: 29 additions & 0 deletions Zend/tests/bug45178.phpt
@@ -0,0 +1,29 @@
--TEST--
Bug #45178 memory corruption on assignment result of "new" by reference
--FILE--
<?php
class Foo {
function __construct() {
$this->error = array($this,$this);
}
}
$a =& new Foo();

class Bar {
function __construct() {
$this->_rme2 = $this;
}
}

$b =& new Bar();
$b->_rme2 = 0;
var_dump($b);
?>
--EXPECTF--
Strict Standards: Assigning the return value of new by reference is deprecated in %sbug45178.php on line 7

Strict Standards: Assigning the return value of new by reference is deprecated in %sbug45178.php on line 15
object(Bar)#%d (1) {
["_rme2"]=>
int(0)
}
2 changes: 2 additions & 0 deletions Zend/zend_compile.c
Expand Up @@ -655,6 +655,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;
}
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_compile.h
Expand Up @@ -600,6 +600,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 */
Expand Down Expand Up @@ -685,6 +686,7 @@ int zendlex(znode *zendlval TSRMLS_DC);


#define ZEND_RETURNS_FUNCTION 1<<0
#define ZEND_RETURNS_NEW 1<<1

END_EXTERN_C()

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_language_parser.y
Expand Up @@ -553,7 +553,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(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 '=' '&' 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); }
| 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); $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(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); }
Expand Down
6 changes: 6 additions & 0 deletions Zend/zend_vm_def.h
Expand Up @@ -1483,6 +1483,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");
Expand All @@ -1491,6 +1493,10 @@ ZEND_VM_HANDLER(39, ZEND_ASSIGN_REF, VAR|CV, VAR|CV)
variable_ptr_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);

if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
(*variable_ptr_ptr)->refcount--;
}

if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
PZVAL_LOCK(*variable_ptr_ptr);
Expand Down
24 changes: 24 additions & 0 deletions Zend/zend_vm_execute.h
Expand Up @@ -12386,6 +12386,8 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
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");
Expand All @@ -12394,6 +12396,10 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);

if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
(*variable_ptr_ptr)->refcount--;
}

if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
PZVAL_LOCK(*variable_ptr_ptr);
Expand Down Expand Up @@ -14388,6 +14394,8 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
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");
Expand All @@ -14396,6 +14404,10 @@ static int ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
variable_ptr_ptr = _get_zval_ptr_ptr_var(&opline->op1, EX(Ts), &free_op1 TSRMLS_CC);
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);

if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
(*variable_ptr_ptr)->refcount--;
}

if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
PZVAL_LOCK(*variable_ptr_ptr);
Expand Down Expand Up @@ -24495,6 +24507,8 @@ static int ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
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");
Expand All @@ -24503,6 +24517,10 @@ static int ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), BP_VAR_W TSRMLS_CC);
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);

if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
(*variable_ptr_ptr)->refcount--;
}

if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
PZVAL_LOCK(*variable_ptr_ptr);
Expand Down Expand Up @@ -26487,6 +26505,8 @@ static int ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
}
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");
Expand All @@ -26495,6 +26515,10 @@ static int ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
variable_ptr_ptr = _get_zval_ptr_ptr_cv(&opline->op1, EX(Ts), BP_VAR_W TSRMLS_CC);
zend_assign_to_variable_reference(variable_ptr_ptr, value_ptr_ptr TSRMLS_CC);

if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_NEW) {
(*variable_ptr_ptr)->refcount--;
}

if (!RETURN_VALUE_UNUSED(&opline->result)) {
EX_T(opline->result.u.var).var.ptr_ptr = variable_ptr_ptr;
PZVAL_LOCK(*variable_ptr_ptr);
Expand Down

0 comments on commit d2f478a

Please sign in to comment.