Hello.
There is a bug in PHP5 code which shows when an object destructor tries to access the 
zval for the object being destroyed. Here is a
sample code:
<?
class A
{
        public function __construct ()
        {
        }

        public function __destruct ()
        {
                global $gA;
        }
}

$gA = new A ();
?>

What happens is that upon program shutdown the symtable is cleared the
refcount for gA zval goes to zero and the zval destructor is called.
It calls the zend_objects_destroy_object() function which has following
code:

...
                ZEND_INIT_SYMTABLE(&symbol_table);

                /* FIXME: Optimize this so that we use the old_object->ce->destructor 
function pointer instead of the name */
                MAKE_STD_ZVAL(destructor_func_name);
                destructor_func_name->type = IS_STRING;
                destructor_func_name->value.str.val = estrndup("__destruct", 
sizeof("__destruct")-1);
                destructor_func_name->value.str.len = sizeof("__destruct")-1;

                call_user_function_ex(NULL, &obj, destructor_func_name, &retval_ptr, 
0, NULL, 0, &symbol_table TSRMLS_CC);

                zend_hash_destroy(&symbol_table);
...

this code sets a temporary symtable and calls the A::__destruct. When the __destruct 
functions
accesses the gA object via "global $gA" its refcount goes from 0 to 1 and after return 
from
"__destruct" the "zend_hash_destroy(&symbol_table);" line kills the symtable, and the 
zval
refcount goes to zero again, this causes the zval structure to be freed, and then it 
is freed
once again on return from zend_objects_destroy_object(), thus causing memory 
corruption.
Here is a patch that fixes the problem:

diff -ruN php5-200310182330.orig/Zend/zend_variables.c 
php5-200310182330/Zend/zend_variables.c
--- php5-200310182330.orig/Zend/zend_variables.c        2003-08-24 18:06:54.000000000 
+0000
+++ php5-200310182330/Zend/zend_variables.c     2003-10-23 19:09:11.000000000 +0000
@@ -58,7 +58,14 @@
                        {
                                TSRMLS_FETCH();

+                               /* Increase temporarily the object zvalue refcount in 
order to protect
+                               the object zvalue from being destroyed one more time 
if it is accessed
+                               from the object destructor call chain. This could 
happen if the
+                               object destructor accesses the object as a global 
variable by name. */
+
+                               zvalue->refcount++;
                                Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
+                               zvalue->refcount--;
                        }
                        break;
                case IS_RESOURCE:

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to