ID: 46025 User updated by: askalski at gmail dot com Reported By: askalski at gmail dot com Status: Open Bug Type: Reproducible crash Operating System: redhat PHP Version: 5.2.6 New Comment:
To assist with implementing a fix: I wrote up a local fix that uses two executor globals: /* HANDLE_BLOCK_INTERRUPTIONS nesting depth */ zend_uint blocking_interruptions; /* true if a bailout was deferred while interruptions were blocked */ zend_bool deferred_bailout; In my testing, I quickly realized that APC in conjunction with Zend was making nested calls to HANDLE_BLOCK_INTERRUPTIONS(), so to keep from unblocking prematurely, it was necessary to track nesting depth. Example from my debugging: Block 0 /tmp/APC-3.0.19/php_apc.c:559 Block 1 /tmp/php-5.2.6/Zend/zend_alloc.c:1876 Unblock 1 /tmp/php-5.2.6/Zend/zend_alloc.c:1913 Unblock 0 /tmp/APC-3.0.19/php_apc.c:592 My updated macros: #define HANDLE_BLOCK_INTERRUPTIONS() if (!EG(blocking_interruptions)++) { if (zend_block_interruptions) { zend_block_interruptions(); } } #define HANDLE_UNBLOCK_INTERRUPTIONS() if (EG(blocking_interruptions) && !--EG(blocking_interruptions)) { if (zend_unblock_interruptions) { zend_unblock_interruptions(); } if (EG(deferred_bailout)) { zend_bailout(); } } And my mod to _zend_bailout: if (EG(blocking_interruptions)) { EG(deferred_bailout) = 1; return; } EG(deferred_bailout) = 0; Previous Comments: ------------------------------------------------------------------------ [2008-09-08 15:23:59] askalski at gmail dot com Description: ------------ A zend_bailout (longjmp) is allowed while HANDLE_BLOCK_INTERRUPTIONS is in effect. When this happens while APC has its shared memory segment locked, it results in corruption of the segment and deadlocking of the mutex. An Apache restart is required to get things moving again. Tested with PHP 5.2.6 and 4.4.8 with APC 3.0.19 using pthread mutexes. In our particular case, this is happening when a script hits the max_execution_time timeout during an include(). Although APC is involved, I am submitting this as a PHP bug because the fix (zend_bailout / HANDLE_BLOCK_INTERRUPTIONS) is completely PHP-side. Reproduce code: --------------- <?php header('Content-Type: text/plain'); echo "Fetching value from APC...\n"; flush(); apc_fetch('deadlock'); echo "Attempting to deadlock APC with max_execution_time...\n"; flush(); ini_set('max_execution_time', 1); for (;;) apc_store('deadlock', 1); ?> Expected result: ---------------- Defer the zend_bailout until HANDLE_UNBLOCK_INTERRUPTIONS is called. Actual result: -------------- Deadlock of the entire web server, requiring an Apache restart. ------------------------------------------------------------------------ -- Edit this bug report at http://bugs.php.net/?id=46025&edit=1