Edit report at http://bugs.php.net/bug.php?id=54157&edit=1
ID: 54157 Comment by: nicolas dot grekas+php at gmail dot com Reported by: tstarling at wikimedia dot org Summary: Destruction of some global variables before session write handler callback Status: Wont fix Type: Bug Package: Scripting Engine problem Operating System: Linux PHP Version: 5.3SVN-2011-03-03 (SVN) Block user comment: N Private report: N New Comment: If you add this to your code, it works around the problem, while still closing the session as late as possible I think : <?php register_shutdown_function('shutdown_session'); function shutdown_session() {register_shutdown_function('session_write_close');} ?> Previous Comments: ------------------------------------------------------------------------ [2011-03-04 10:19:49] johan...@php.net This is a hen and egg problem. First issue which comes to mind is: What happens if a destructor wants to log it's state or such in the session? We have tuned the order multiple times and the current behaviour is the best of the bad choices we have. ------------------------------------------------------------------------ [2011-03-04 01:29:20] tstarling at wikimedia dot org Here's another argument in favour of adding a new hook to php_request_shutdown(): the point of session_set_save_handler() is to allow userspace code to implement alternative methods of session storage. Writing to alternate storage will typically involve calling some other PHP module. But how can we safely call other PHP modules when half of them will have had their RSHUTDOWN functions called? There is the potential for subtle bugs dependent on module load order: dangling pointers, memory corruption, etc. ------------------------------------------------------------------------ [2011-03-04 00:54:47] tstarling at wikimedia dot org Description: ------------ The request function of the session module calls custom session save handlers. Because modules are shut down after zend_call_destructors() is called, this exposes the weird and apparently broken behaviour of zend_call_destructors() to the user space. Its effect is to delete all global variables with a reference count of 1, but only if they hold an object. Global variables which are referenced from anywhere, including other global variables, are not deleted. Ideally, I would like session save handlers to have reliable access to global variables. That probably means calling them before the user-defined __destruct() functions, say with an extra hook into php_request_shutdown(). Failing that, I would like the behaviour to be consistent and predictable, so that we don't end up with strange regressions like the one observed here: http://www.mediawiki.org/wiki/Special:Code/MediaWiki/83140#c14601 Test script: --------------- <?php function noop() {} function save() { debug_zval_dump( $GLOBALS['a'] ); debug_zval_dump( $GLOBALS['b'] ); debug_zval_dump( $GLOBALS['c'] ); } class Foo {} $a = new Foo; $b = new Foo; $c =& $b; session_set_save_handler( 'noop', 'noop', 'noop', 'save', 'noop', 'noop' ); session_start(); Expected result: ---------------- object(Foo)#1 (0) refcount(2){ } object(Foo)#2 (0) refcount(1){ } object(Foo)#2 (0) refcount(1){ } Actual result: -------------- Notice: Undefined index: a in /home/tstarling/src/php/stuff/weird-shutdown_destructors.php on line 5 NULL refcount(1) object(Foo)#2 (0) refcount(1){ } object(Foo)#2 (0) refcount(1){ } ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/bug.php?id=54157&edit=1