]> granicus.if.org Git - php/commitdiff
Fixed bug #45178 (memory corruption on assignment result of "new" by reference)
authorDmitry Stogov <dmitry@php.net>
Thu, 24 Jul 2008 11:47:14 +0000 (11:47 +0000)
committerDmitry Stogov <dmitry@php.net>
Thu, 24 Jul 2008 11:47:14 +0000 (11:47 +0000)
NEWS
Zend/tests/bug45178.phpt [new file with mode: 0755]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_language_parser.y
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index 7b987d6c1f59f08919d2707e9f3021542fff4147..a9643eebcf7e3a09e08ea1bb24a1a90da3d55a16 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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).
diff --git a/Zend/tests/bug45178.phpt b/Zend/tests/bug45178.phpt
new file mode 100755 (executable)
index 0000000..156a5a7
--- /dev/null
@@ -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)
+}
index ea59a921447bba19fcc4130fc62f6d4ae3226cc7..22a7135e2111aeb5c841bc54a2b4b451d9428a41 100644 (file)
@@ -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;
        }
index 191d8224a2b804dcd3367573e6f1920bb19fcdf5..6ebdd2d0e2e9f2b419217fe0555fa9c6b8cee40c 100644 (file)
@@ -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 */
@@ -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()
 
index 5094c9f4a6dedb8075126536b79756305812c654..6e26796e445371f783dc49c6885e4474ce4ea8ea 100644 (file)
@@ -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); }
index 4ea3dea5b314d751e64817b87e66596d2c1e7fde..7083bb43fe044cca1e010d0a57e56b2fc0e5101b 100644 (file)
@@ -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");
@@ -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);
index 79e1a1067582a270d4a9ce9f278d552e8f33e992..6488e85db89c3b489b8e84da08471c5aa1dcd2fe 100644 (file)
@@ -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");
@@ -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);
@@ -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");
@@ -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);
@@ -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");
@@ -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);
@@ -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");
@@ -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);