Edit report at http://bugs.php.net/bug.php?id=52389&edit=1
ID: 52389 User updated by: miroslav dot zacek at skype dot net Reported by: miroslav dot zacek at skype dot net Summary: Memory (de)allocation problem for pgsql notices -Status: Feedback +Status: Open Type: Bug Package: PostgreSQL related Operating System: Linux (Kubuntu) PHP Version: 5.3.2 Block user comment: N New Comment: Thanks Jaromir :-) Previous Comments: ------------------------------------------------------------------------ [2010-10-18 13:19:45] jaromir dot dolecek at skype dot net Trigger script (must replace DBNAME and USER with proper info): <?php $c = pg_connect("host=localhost port=6001 dbname=DBNAME user=USER"); function nop() { } function trigger_notice() { global $c; $rv2 = pg_query($c, 'SELECT * FROM foo()'); } $rv = pg_query($c, 'CREATE OR REPLACE FUNCTION foo() RETURNS integer AS $$ BEGIN RAISE NOTICE \'foo\'; RETURN 3; END $$ LANGUAGE \'plpgsql\' VOLATILE'); session_set_save_handler('nop', 'nop', 'nop', 'trigger_notice', 'nop', 'nop'); session_start(); ------------------------------------------------------------------------ [2010-10-18 13:18:33] jaromir dot dolecek at skype dot net This problem happens due to interaction with user session save handler and pgsql extension. Repeat script is included as next comment. So after further analysis, this is what happens: 1. request ends, PHP runs RSHUTDOWN method of individual modules in reverse order than loaded - i.e. pgsql (dynamically loaded) before session (which is builtin) 2. pgsql RSHUTDOWN is called, PGG(notices) is cleared 3. session RSHUTDOWN is called, which runs user session save method, invoking pgsql code 4. if sql query generates notice, message is added to PGG(notices) using non-persistent memory 5. new notice stays in PGG(notice) after RSHUTDOWN process is finished, the non-persistent memory is cleared automatically by PHP, leaving PGG(notices) with dangling pointer On next request, this is what happens: 1. when pgsql RSHUTDOWN is called, code tries to remove the stale entry 2. the pointer is no longer valid, so random memory is overwritten (either double free if the memory happens to point to newly allocated valid value, or just random memory) Problem happens only when using PHP as Apache module or FastCGI - it needs the same process to process at least two separate requests. That's also reason why the crash never happens for first request. Proper fix is for session code to not abuse RSHUTDOWN for running session store. Similar problem might happen for other modules with local deinicialization in RSHUTDOWN method. I know it's documented that session_write_close() should be called explicitly, but PHP interpreter should not allow this to happen - session code should not invoke user code in RSHUTDOWN. To make explicit and force people fix code, it should issue some PHP warning if session is still active in RSHUTDOWN. Bandaid fix for pgsql is included in pgsql-fixed.diff. Note it generates some memory leaks warnings with DEBUG, but that is not possible to avoid when session runs after pgsql cleanup. ------------------------------------------------------------------------ [2010-10-18 12:56:41] jaromir dot dolecek at skype dot net I've uploaded revised patch - the previous version has crash problem with pg_last_error(), because _php_pgsql_trim_message() was also used in context, where non-persistent return value was expected I'll post the repeat PHP skript and some analysis shortly. ------------------------------------------------------------------------ [2010-08-26 11:35:41] miroslav dot zacek at skype dot net I tried to create a simple test that crashes but it is not so easy. More complex page with several requests and session in DB crashes (not always, several reloads are needed usually). I'll try to create it but I'm quite busy now so it won't be that fast. Sorry. ------------------------------------------------------------------------ [2010-08-14 01:13:49] fel...@php.net Thank you for this bug report. To properly diagnose the problem, we need a short but complete example script to be able to reproduce this bug ourselves. A proper reproducing script starts with <?php and ends with ?>, is max. 10-20 lines long and does not require any external resources such as databases, etc. If the script requires a database to demonstrate the issue, please make sure it creates all necessary tables, stored procedures etc. Please avoid embedding huge scripts into the report. Have you tried it without Suhosin? ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at http://bugs.php.net/bug.php?id=52389 -- Edit this bug report at http://bugs.php.net/bug.php?id=52389&edit=1