dmitry                                   Fri, 01 Oct 2010 09:49:20 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=303913

Log:
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)

Bug: http://bugs.php.net/52879 (Assigned) Objects unreferenced in __get, __set, 
__isset or __unset can be freed too early
      
Changed paths:
    U   php/php-src/branches/PHP_5_2/NEWS
    A   php/php-src/branches/PHP_5_2/Zend/tests/bug52879.phpt
    U   php/php-src/branches/PHP_5_2/Zend/zend_object_handlers.c
    U   php/php-src/branches/PHP_5_3/NEWS
    A   php/php-src/branches/PHP_5_3/Zend/tests/bug52879.phpt
    U   php/php-src/branches/PHP_5_3/Zend/zend_object_handlers.c
    A   php/php-src/trunk/Zend/tests/bug52879.phpt
    U   php/php-src/trunk/Zend/zend_object_handlers.c

Modified: php/php-src/branches/PHP_5_2/NEWS
===================================================================
--- php/php-src/branches/PHP_5_2/NEWS	2010-10-01 09:18:44 UTC (rev 303912)
+++ php/php-src/branches/PHP_5_2/NEWS	2010-10-01 09:49:20 UTC (rev 303913)
@@ -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).

Added: php/php-src/branches/PHP_5_2/Zend/tests/bug52879.phpt
===================================================================
--- php/php-src/branches/PHP_5_2/Zend/tests/bug52879.phpt	                        (rev 0)
+++ php/php-src/branches/PHP_5_2/Zend/tests/bug52879.phpt	2010-10-01 09:49:20 UTC (rev 303913)
@@ -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

Modified: php/php-src/branches/PHP_5_2/Zend/zend_object_handlers.c
===================================================================
--- php/php-src/branches/PHP_5_2/Zend/zend_object_handlers.c	2010-10-01 09:18:44 UTC (rev 303912)
+++ php/php-src/branches/PHP_5_2/Zend/zend_object_handlers.c	2010-10-01 09:49:20 UTC (rev 303913)
@@ -329,6 +329,9 @@
 		    !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 @@
 			}
 		}
 	} 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 @@
 		    !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 @@

 			/* 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) {

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2010-10-01 09:18:44 UTC (rev 303912)
+++ php/php-src/branches/PHP_5_3/NEWS	2010-10-01 09:49:20 UTC (rev 303913)
@@ -37,6 +37,8 @@
   expected). (Stas)
 - Fixed bug #52891 (Wrong data inserted with mysqli/mysqlnd when using
   mysqli_stmt_bind_param and value> PHP_INT_MAX). (Andrey)
+- 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 #52849 (GNU MP invalid version match). (Adam)
 - Fixed bug #52843 (Segfault when optional parameters are not passed in to
   mssql_connect). (Felipe)

Added: php/php-src/branches/PHP_5_3/Zend/tests/bug52879.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/tests/bug52879.phpt	                        (rev 0)
+++ php/php-src/branches/PHP_5_3/Zend/tests/bug52879.phpt	2010-10-01 09:49:20 UTC (rev 303913)
@@ -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

Modified: php/php-src/branches/PHP_5_3/Zend/zend_object_handlers.c
===================================================================
--- php/php-src/branches/PHP_5_3/Zend/zend_object_handlers.c	2010-10-01 09:18:44 UTC (rev 303912)
+++ php/php-src/branches/PHP_5_3/Zend/zend_object_handlers.c	2010-10-01 09:49:20 UTC (rev 303913)
@@ -347,6 +347,9 @@
 		    !guard->in_get) {
 			/* have getter - try with it! */
 			Z_ADDREF_P(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;
@@ -445,22 +448,22 @@
 			}
 		}
 	} else {
-		int setter_done = 0;
 		zend_guard *guard = NULL;

 		if (zobj->ce->__set &&
 		    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
 		    !guard->in_set) {
 			Z_ADDREF_P(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 */
@@ -643,6 +646,9 @@
 		    !guard->in_unset) {
 			/* have unseter - try with it! */
 			Z_ADDREF_P(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;
@@ -1169,6 +1175,9 @@

 			/* have issetter - try with it! */
 			Z_ADDREF_P(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) {

Added: php/php-src/trunk/Zend/tests/bug52879.phpt
===================================================================
--- php/php-src/trunk/Zend/tests/bug52879.phpt	                        (rev 0)
+++ php/php-src/trunk/Zend/tests/bug52879.phpt	2010-10-01 09:49:20 UTC (rev 303913)
@@ -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

Modified: php/php-src/trunk/Zend/zend_object_handlers.c
===================================================================
--- php/php-src/trunk/Zend/zend_object_handlers.c	2010-10-01 09:18:44 UTC (rev 303912)
+++ php/php-src/trunk/Zend/zend_object_handlers.c	2010-10-01 09:49:20 UTC (rev 303913)
@@ -419,6 +419,9 @@
 		    !guard->in_get) {
 			/* have getter - try with it! */
 			Z_ADDREF_P(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;
@@ -525,30 +528,22 @@
 			}
 		}
 	} else {
-		int setter_done = 0;
 		zend_guard *guard = NULL;

 		if (zobj->ce->__set &&
 		    zend_get_property_guard(zobj, property_info, member, &guard) == SUCCESS &&
 		    !guard->in_set) {
 			Z_ADDREF_P(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);
-		} else if (zobj->ce->__set && guard && guard->in_set == 1) {
-			if (Z_STRVAL_P(member)[0] == '\0') {
-				if (Z_STRLEN_P(member) == 0) {
-					zend_error(E_ERROR, "Cannot access empty property");
-				} else {
-					zend_error(E_ERROR, "Cannot access property started with '\\0'");
-				}
-			}
-		}
-		if (!setter_done && EXPECTED(property_info != NULL)) {
+		} else if (EXPECTED(property_info != NULL)) {
 			/* if we assign referenced variable, we should separate it */
 			Z_ADDREF_P(value);
 			if (PZVAL_IS_REF(value)) {
@@ -556,19 +551,27 @@
 			}
 			if (EXPECTED((property_info->flags & ZEND_ACC_STATIC) == 0) &&
 			    property_info->offset >= 0) {
-				if (!zobj->properties) {
-					zobj->properties_table[property_info->offset] = value;
-				} else if (zobj->properties_table[property_info->offset]) {
-					*(zval**)zobj->properties_table[property_info->offset] = value;
+					if (!zobj->properties) {
+						zobj->properties_table[property_info->offset] = value;
+					} else if (zobj->properties_table[property_info->offset]) {
+						*(zval**)zobj->properties_table[property_info->offset] = value;
+					} else {
+						zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]);
+					}
 				} else {
-					zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), (void**)&zobj->properties_table[property_info->offset]);
-				}
-			} else {
-				if (!zobj->properties) {
+					if (!zobj->properties) {
 					rebuild_object_properties(zobj);
 				}
 				zend_hash_quick_update(zobj->properties, property_info->name, property_info->name_length+1, property_info->h, &value, sizeof(zval *), NULL);
 			}
+		} else if (zobj->ce->__set && guard && guard->in_set == 1) {
+			if (Z_STRVAL_P(member)[0] == '\0') {
+				if (Z_STRLEN_P(member) == 0) {
+					zend_error(E_ERROR, "Cannot access empty property");
+				} else {
+					zend_error(E_ERROR, "Cannot access property started with '\\0'");
+				}
+			}
 		}
 	}

@@ -770,6 +773,9 @@
 		    !guard->in_unset) {
 			/* have unseter - try with it! */
 			Z_ADDREF_P(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;
@@ -1371,6 +1377,9 @@

 			/* have issetter - try with it! */
 			Z_ADDREF_P(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) {
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to