ID: 38315
Updated by: [EMAIL PROTECTED]
Reported By: [EMAIL PROTECTED]
-Status: Open
+Status: Assigned
Bug Type: Scripting Engine problem
Operating System: Linux (N/A)
PHP Version: 5.1.4
-Assigned To:
+Assigned To: dmitry
New Comment:
Dmitry, could you plz check it out?
Previous Comments:
------------------------------------------------------------------------
[2006-08-03 18:03:10] [EMAIL PROTECTED]
This happens because of the following code segment in function
zend_objects_store_call_destructors:
for (i = 1; i < objects->top ; i++) {
if (objects->object_buckets[i].valid) {
....
obj->dtor(obj->object, i TSRMLS_CC);
The problem being that the destructor allocates a new object, which due
to chance puts the new object in objects->object_buckets[2]
This dtor call originated from the
zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t)
zval_call_destructor TSRMLS_CC);
for the element in the global scope.
Then after object#2 has been inserted into the objects store, by the
dtor of #1
zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
again starts to walk the objects->object_buckets to dtor the objects.
It discovers object#2 and calls the dtor, which yet again constructs a
new object, which yet again occupies bucket 1 of the objects_store
(call it object#1a). This bucket is passed over already in the loop and
the current call_destructors will never destroy this object.
Then, zend_hash_graceful_reverse_destroy(&EG(symbol_table));
in zend_execute_API.c:235 again hits the symbol tables, to discover
object#1a. Calls the dtor, which allocates object#3.
zend_objects_store_free_object_storage is called during
shutdown_executor and which free(object#3) without calling its
destructor.
Now, there are two problems here. One, the object bucket loop does not
handle self-modifying destructors. Maybe a linking the buckets, like
the usual hashes maintain order in php, might help. Now, I don't know
how erealloc works, but the self-modifying nature might have further
problems if EG(objects_store).object_buckets is moved while the
following "local" value (obj) isn't, in function
zend_objects_store_del_ref():
obj = &EG(objects_store).object_buckets[handle].bucket.obj;
....
obj->dtor(obj->object, handle TSRMLS_CC);
....
if (obj->refcount == 1) {
if (obj->free_storage) {
Second, the free_storage code does not check if the bucket destructor
was called.
And finally, why the hell do you call them buckets when they are just
arrays indexed by integer offsets ? (confused me into thinking they
were chained hashes for a while).
I hope I understood everything right.
------------------------------------------------------------------------
[2006-08-03 15:55:50] [EMAIL PROTECTED]
Description:
------------
Hi,
I already discussed this with Gopal, so he'll probably have something
more enlightening to say about it.
When calling a class' constructor from one of its object's destructors,
the engine behaves strangely.
I expected it to recurse forever and segfault like PHP normally does on
infinite recursion.
Yes, I know I /shouldn't/ be doing this. I just want to make sure
something bad isn't happening internally (and document this
behaviour).
S
Reproduce code:
---------------
class Foo {
function __construct() { echo "constructing\n"; }
function __destruct() { $GLOBALS['foo'] = new Foo(); }
}
$foo = new Foo();
Expected result:
----------------
constructing
constructing
... (some large number of times)
constructing
constructing
[[Segmentation Fault]]
Actual result:
--------------
constructing
constructing
constructing
constructing
(yes, only 4 times. 4 is a strange number here, no?)
------------------------------------------------------------------------
--
Edit this bug report at http://bugs.php.net/?id=38315&edit=1