ID:               38315
 Updated by:       [EMAIL PROTECTED]
 Reported By:      [EMAIL PROTECTED]
-Status:           Assigned
+Status:           Closed
 Bug Type:         Scripting Engine problem
 Operating System: Linux (N/A)
 PHP Version:      5.1.4
 Assigned To:      dmitry
 New Comment:

The bug is fixed in CVS HEAD and PHP_5_2.


Previous Comments:
------------------------------------------------------------------------

[2006-08-03 18:47:19] [EMAIL PROTECTED]

Dmitry, could you plz check it out?

------------------------------------------------------------------------

[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

Reply via email to