[PATCH] Memory corruption when freeing an object zval twice
| From: | Vesselin Atanasov | Date: | Thu, 23 Oct 2003 17:20:13 +0000 |
| Subject: | [PATCH] Memory corruption when freeing an object zval twice | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-4947@lists.php.net to get a copy of this message | ||
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: