]> granicus.if.org Git - php/commitdiff
Fixed bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be...
authorDmitry Stogov <dmitry@php.net>
Fri, 1 Oct 2010 09:49:20 +0000 (09:49 +0000)
committerDmitry Stogov <dmitry@php.net>
Fri, 1 Oct 2010 09:49:20 +0000 (09:49 +0000)
NEWS
Zend/tests/bug52879.phpt [new file with mode: 0644]
Zend/zend_object_handlers.c

diff --git a/NEWS b/NEWS
index 93fa9ccb837574fdc526d75b34a62299cb4f6e4b..c00f86205a95e96aec719c1442c6cc6fd9a52278 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,8 @@
 
 - Fixed bug #52929 (Segfault in filter_var with FILTER_VALIDATE_EMAIL with
   large amount of data). (Adam)
+- Fixed bug #52879 (Objects unreferenced in __get, __set, __isset or __unset
+  can be freed too early). (mail_ben_schmidt at yahoo dot com dot au, Dmitry)
 - Fixed bug #52772 (var_dump() doesn't check for the existence of 
   get_class_name before calling it). (Kalle, Gustavo)
 - Fixed bug #52546 (pdo_dblib segmentation fault when iterating MONEY values).
diff --git a/Zend/tests/bug52879.phpt b/Zend/tests/bug52879.phpt
new file mode 100644 (file)
index 0000000..0193be4
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+Bug #52879 (Objects unreferenced in __get, __set, __isset or __unset can be freed too early)
+--FILE--
+<?php
+class MyClass {
+       public $myRef;
+       public function __set($property,$value) {
+               $this->myRef = $value;
+       }
+}
+$myGlobal=new MyClass($myGlobal);
+$myGlobal->myRef=&$myGlobal;
+$myGlobal->myNonExistentProperty="ok\n";
+echo $myGlobal;
+--EXPECT--
+ok
index 8679daf6b68af469a57a0ea08b9da41a7accce71..271c79f8dfe6b3d848acd549125216eda982d13b 100644 (file)
@@ -329,6 +329,9 @@ zval *zend_std_read_property(zval *object, zval *member, int type TSRMLS_DC)
                    !guard->in_get) {
                        /* have getter - try with it! */
                        ZVAL_ADDREF(object);
+                       if (PZVAL_IS_REF(object)) {
+                               SEPARATE_ZVAL(&object);
+                       }
                        guard->in_get = 1; /* prevent circular getting */
                        rv = zend_std_call_getter(object, member TSRMLS_CC);
                        guard->in_get = 0;
@@ -418,22 +421,22 @@ static void zend_std_write_property(zval *object, zval *member, zval *value TSRM
                        }
                }
        } else {
-               int setter_done = 0;
                zend_guard *guard;
 
                if (zobj->ce->__set &&
                    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
                    !guard->in_set) {
                        ZVAL_ADDREF(object);
+                       if (PZVAL_IS_REF(object)) {
+                               SEPARATE_ZVAL(&object);
+                       }
                        guard->in_set = 1; /* prevent circular setting */
                        if (zend_std_call_setter(object, member, value TSRMLS_CC) != SUCCESS) {
                                /* for now, just ignore it - __set should take care of warnings, etc. */
                        }
-                       setter_done = 1;
                        guard->in_set = 0;
                        zval_ptr_dtor(&object);
-               }
-               if (!setter_done && property_info) {
+               } else if (property_info) {
                        zval **foo;
 
                        /* if we assign referenced variable, we should separate it */
@@ -611,6 +614,9 @@ static void zend_std_unset_property(zval *object, zval *member TSRMLS_DC)
                    !guard->in_unset) {
                        /* have unseter - try with it! */
                        ZVAL_ADDREF(object);
+                       if (PZVAL_IS_REF(object)) {
+                               SEPARATE_ZVAL(&object);
+                       }
                        guard->in_unset = 1; /* prevent circular unsetting */
                        zend_std_call_unsetter(object, member TSRMLS_CC);
                        guard->in_unset = 0;
@@ -1042,6 +1048,9 @@ static int zend_std_has_property(zval *object, zval *member, int has_set_exists
 
                        /* have issetter - try with it! */
                        ZVAL_ADDREF(object);
+                       if (PZVAL_IS_REF(object)) {
+                               SEPARATE_ZVAL(&object);
+                       }
                        guard->in_isset = 1; /* prevent circular getting */
                        rv = zend_std_call_issetter(object, member TSRMLS_CC);
                        if (rv) {