zend_list_delete() doesn't.
| From: | Sara Golemon | Date: | Thu, 08 Sep 2005 00:33:19 +0000 |
| Subject: | zend_list_delete() doesn't. | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-18704@lists.php.net to get a copy of this message | ||
Certain things you take for granted:
The sun will come up.
Politicians are dishonest.
Resource destruction functions (fclose(), mysql_disconnect(), etc...) will actually shutdown their resources.
Guess which of those three you can't count on.
Seems that zend_list_delete(), which I (and many other extension writers) have relied on to actually delete list_entry objects from the resource hash, doesn't actually delete so much as it delref's. In general use cases this isn't really a problem since most resource IDs are only referenced once (by the zval* they were initially stored into). So calling zend_list_delete() in those cases actually does destroy it since --le->refcount == 0.
Using a very simple (and not entirely unlikely) bit of userspace code to force zval separation however, means that the first call to zend_list_delete() won't actually delete the resource. Consider this reproduction snippet:
<?php
$fp1 = fopen('test', 'w');
$fp2 = $fp1; /* Still a single zval* and le->refcount == 1 */
$fp3 = &$fp1; /* Two zval*s now and le->refcount == 2 */
fclose($fp1);
/* le->refcount now == 1, and the file is still open
File operations on $fp1, $fp2, or $fp3 will all succeed */?> Calling either unset($fp1); or unset($fp3); at this point would not trigger the destruction, however calling either both of them or just unset($fp2); alone would. Calling fclose() a second time on any of the variables would also work. This behavior isn't unique to fclose(), several extensions which implement the resource type rely on zend_list_delete() in this way, and the specific naming of this function makes me a little curious: Did zend_list_delete() used to behave differently? Is there a specific motivation against modifying it to act like a genuine delete, then implementing a zend_list_delref() which behaves like the current zend_list_delete(), and modifying zval_dtor() implementations to use that instead. Am I the only one mislead by the purpose of zend_list_delete()? -Sara