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