Bug #31749 [Com]: deadlock due to libc mutexes not released when timeout signal is delivered

From: Date: Thu, 17 Nov 2011 01:34:38 +0000
Subject: Bug #31749 [Com]: deadlock due to libc mutexes not released when timeout signal is delivered
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-165276@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=31749&edit=1

 ID:                 31749
 Comment by:         tstarling@php.net
 Reported by:        phpbug2 at mailinator dot com
 Summary:            deadlock due to libc mutexes not released when
                     timeout signal is delivered
 Status:             Re-Opened
 Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   Linux 2.4.28, 2.4.21-SMP
 PHP Version:        5CVS, 4CVS (2005-06-19)
 Assigned To:        dmitry
 Block user comment: N
 Private report:     N

 New Comment:

I added a workaround to our custom error handler:

https://www.mediawiki.org/wiki/Special:Code/MediaWiki/103433


Previous Comments:
------------------------------------------------------------------------
[2011-11-16 10:22:13] tstarling@php.net

The suggested patch is an improvement, but it still calls zend_timeout() when the "hard
timeout" is reached, which will usually deadlock if a libc mutex such as the one for malloc()
is held. The only safe way to handle this situation is to kill the process without calling any
non-signal-safe functions, e.g. by calling abort(). If you return control to Apache using longjmp()
(like what zend_bailout() does), Apache will deadlock instead. I haven't found any robust way
to display an error message, it would look the same as a segfault to the user.

------------------------------------------------------------------------
[2010-06-08 13:27:41] michael at makeweb dot no

I have the same problem, reproduced on php 4.4.9 and 5.3.0.

Basically pseudocode to reproduce is set_time_limit(1); do { ... } until time passed = 1 second.

This will create a race condition where sometimes a libc lock will prevent zend_timeout to process
properly.

Script to reproduce on 5.3.0: ($limit is not 1, because php seems to not break accurately on time -
this value must be adjusted so the error "PHP Fatal error:  Maximum execution time of 1 second
exceeded in Unknown on line 0" frequently appears. The script should fail within 100 runs (lock
up).

<?php
  echo "Trying to break php...\n";
  set_time_limit(1);
  $limit = 1.235;
  $start = array_sum(explode(' ',$x = microtime()));
  $a = array();
  for ($cnt = 0; $cnt < 10; $cnt++) {
    for ($cntb = 0; $cntb < 100; $cntb++) {
      for ($cntc = 0; $cntc < 100; $cntc++) {
        $end = array_sum(explode(' ',$y = microtime()));
        $a[$cnt][$cntb][$cntc] = md5($cnt.$cntb.$cntc);
        if ($end >= $start+$limit) break;   
      }
      if ($end >= $start+$limit) break;   
    }
    if ($end >= $start+$limit) break;   
  }
  echo "$x - $y (".($end-$start).")\n";
?>

run with: while [ true ]; do php break.php; done

Though this scenario is unlikely, there are other cases where it can happen very often, however I
fail to come up with a short example of it. The reason for generating a multidimensional array is
that in php4, the hang is very likely to happen within zend_shutdown, as the resources are freed
(hangs within 1-10 cycles)

Keep in mind error logging has to be enabled (this is when there's calls for libc "get
time" which causes the locking issue within zend_timeout)

pstack for php 5.3.0:

# pstack 1565
#0  0x00319402 in __kernel_vsyscall ()
#1  0x001dede3 in __lll_lock_wait_private () from /lib/libc.so.6
#2  0x0016e6f6 in _L_lock_15330 () from /lib/libc.so.6
#3  0x0016dbb4 in free () from /lib/libc.so.6
#4  0x0012067c in setlocale () from /lib/libc.so.6
#5  0x08084586 in seek_to_tz_position ()
#6  0x08084664 in timelib_timezone_id_is_valid ()
#7  0x0806575c in guess_timezone ()
#8  0x080657a5 in get_timezone_info ()
#9  0x08067f35 in php_format_date ()
#10 0x082ab96e in php_log_err ()
#11 0x082abe17 in php_error_cb ()
#12 0x082f9fe8 in zend_error_noreturn ()
#13 0x082ec745 in zend_timeout ()
#14 <signal handler called>
#15 0x00169c49 in _int_free () from /lib/libc.so.6
#16 0x0016dbc0 in free () from /lib/libc.so.6
#17 0x082ac6df in php_conv_fp ()
#18 0x082ad409 in strx_printv ()
#19 0x082ad804 in ap_php_snprintf ()
#20 0x082565f2 in _php_gettimeofday ()
#21 0x08342509 in zend_do_fcall_common_helper_SPEC ()
#22 0x08319f3d in execute ()
#23 0x082f8e47 in zend_execute_scripts ()
#24 0x082a92be in php_execute_script ()
#25 0x08378457 in main ()

Any suggestions how to patch php4 be greatly appreciated!

Michael

------------------------------------------------------------------------
[2008-07-21 01:00:00] php-bugs at lists dot php dot net

No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".

------------------------------------------------------------------------
[2008-07-13 15:51:47] jani@php.net

Please try using this CVS snapshot:

  http://snaps.php.net/php5.2-latest.tar.gz
 
For Windows (zip):
 
  http://snaps.php.net/win32/php5.2-win32-latest.zip

For Windows (installer):

  http://snaps.php.net/win32/php5.2-win32-installer-latest.msi



------------------------------------------------------------------------
[2005-12-24 02:46:25] sniper@php.net

Dmitry, can you check this out please?

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


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

    https://bugs.php.net/bug.php?id=31749


-- 
Edit this bug report at https://bugs.php.net/bug.php?id=31749&edit=1


Thread (24 messages)

« previous php.bugs (#165276) next »