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