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
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php