ID:               46025
 Comment by:       dan at archlinux dot org
 Reported By:      askalski at gmail dot com
 Status:           Suspended
 Bug Type:         Reproducible crash
 Operating System: redhat
 PHP Version:      5.2.6
 New Comment:

Any progress here? This is definitely reproducible and we have seen it
on archlinux.org about once every 3 or 4 days- it kind of stinks. Is
there any current workaround besides increasing the timeout value and
hoping for the best?

Running:
Apache 2.2.11
PHP 5.2.8
APC 3.0.19


Previous Comments:
------------------------------------------------------------------------

[2008-09-09 00:46:09] scott...@php.net

This is essentially what http://wiki.php.net/rfc/zendsignals is for, it
was considered for PHP 5.3 but has been deferred for the moment.

------------------------------------------------------------------------

[2008-09-08 23:56:04] askalski at gmail dot com

Reproduced with latest checkouts from both the PHP_5_2 and PHP_5_3
tags.

X-Powered-By: PHP/5.2.7-dev
X-Powered-By: PHP/5.3.0alpha3-dev

------------------------------------------------------------------------

[2008-09-08 21:16:43] j...@php.net

Can you reproduce this with latest CVS checkout of PHP_5_2 (and 
preferrably PHP_5_3) ??

------------------------------------------------------------------------

[2008-09-08 20:50:12] askalski at gmail dot com

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;

------------------------------------------------------------------------

[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

Reply via email to