php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71129 Segmentation fault on ZTS Embed SAPI
Submitted: 2015-12-15 15:46 UTC Modified: 2017-04-09 04:22 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:0 (0.0%)
Same OS:1 (50.0%)
From: maroszek at gmx dot net Assigned:
Status: No Feedback Package: Reproducible crash
PHP Version: 7.0.0 OS: OS X 10.11
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2015-12-15 15:46 UTC] maroszek at gmx dot net
Description:
------------
PHP 7 is current stable
PHP 7 is build as a static library

./configure '--disable-fpm' '--disable-cgi' '--disable-cli' '--enable-embed=static' '--enable-maintainer-zts' '--without-iconv'

g++ --version
> Apple LLVM version 7.0.2 (clang-700.1.81)
> Target: x86_64-apple-darwin15.2.0
> Thread model: posix

I build a simple example to demonstrate the threading problem. 
On OS X the example crashes within a second. 

Sourcecode: https://gist.github.com/paresy/b4babb919a86e9764bc4

Copy crash.cpp into your php7 folder.
Compile with: g++ crash.cpp -Imain -Itsrm -Izend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv

empty.php:
<?

Start it. It should crash. :-)

PS: PHP 5.5 and probably 5.6 is affected as well.

Expected result:
----------------
No crash. Endless loop doing the work. 

Actual result:
--------------
Segmentation fault: 11

and a lot of warnings which make no real sense:
<b>Fatal error</b>:  Maximum execution time of 30 seconds exceeded in <b>Unknown</b> on line <b>0</b><br />

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-12-15 19:41 UTC] maroszek at gmx dot net
I reproduced the problem under Debian 8 aswell.

uname -a 
Linux debian 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt11-1+deb8u5 (2015-10-09) x86_64 GNU/Linux

g++ --version
> g++ (Debian 4.9.2-10) 4.9.2

Here is the output from gdb:
Program received signal SIGSEGV, Segmentation fault.
zend_mm_free_heap (ptr=0xecaff0, heap=0x7fffec000040)
    at /home/user/Downloads/php-7.0.0/Zend/zend_alloc.c:1400
1400			ZEND_MM_CHECK(chunk->heap == heap, "zend_mm_heap corrupted");

Backtrace:
#0  zend_mm_free_heap (ptr=0xecaff0, heap=0x7fffec000040)
    at /home/user/Downloads/php-7.0.0/Zend/zend_alloc.c:1400
#1  _efree (ptr=0xecaff0)
    at /home/user/Downloads/php-7.0.0/Zend/zend_alloc.c:2458
#2  0x0000000000489d65 in zend_string_release (s=<optimized out>)
    at /home/user/Downloads/php-7.0.0/Zend/zend_string.h:271
#3  _zend_hash_del_el_ex (prev=<optimized out>, p=<optimized out>, 
    idx=<optimized out>, ht=<optimized out>)
    at /home/user/Downloads/php-7.0.0/Zend/zend_hash.c:986
#4  _zend_hash_del_el (p=0x7fffec056100, idx=0, ht=0x7fffd4024370)
    at /home/user/Downloads/php-7.0.0/Zend/zend_hash.c:1016
#5  zend_hash_graceful_reverse_destroy (ht=0x7fffd4024370)
    at /home/user/Downloads/php-7.0.0/Zend/zend_hash.c:1468
#6  0x0000000000468995 in shutdown_executor ()
    at /home/user/Downloads/php-7.0.0/Zend/zend_execute_API.c:277
#7  0x0000000000478798 in zend_deactivate ()
    at /home/user/Downloads/php-7.0.0/Zend/zend.c:967
#8  0x0000000000419239 in php_request_shutdown (dummy=<optimized out>)
    at /home/user/Downloads/php-7.0.0/main/main.c:1810
#9  0x0000000000415893 in main::{lambda()#1}::operator()() const ()
 [2015-12-18 07:20 UTC] maroszek at gmx dot net
Can i provide any more details? Can you reproduce the example?

Thank you for your effort and time!
 [2015-12-18 11:41 UTC] ab@php.net
-Status: Open +Status: Feedback
 [2015-12-18 11:41 UTC] ab@php.net
Thanks for the report. Currently the code you posted does not compile with gcc, what i have is 

g++ crash.cpp -Imain -ITSRM -IZend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv
crash.cpp:95:1: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
 };
 ^
crash.cpp:95:1: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
/usr/bin/ld: libs/libphp7.a(zend_API.o): undefined reference to symbol 'dlclose@@GLIBC_2.2.5'
//lib/x86_64-linux-gnu/libdl.so.2: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

Same parameters as yours, Jessie 64-bit. PHP compiled with the options you gave. Could you please check?

Thanks.
 [2015-12-18 12:04 UTC] maroszek at gmx dot net
Hi! Thanks for verifying! For Debian you need to change it a bit.

This should work:
g++ crash.cpp -Imain -ITSRM -IZend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv -ldl -pthread
 [2015-12-18 13:27 UTC] ab@php.net
Thanks for the update. Yeah, now it works. Please check whether this fixes the issue on your side

diff --git a/Zend/zend.c b/Zend/zend.c
index ec520b8..e122b04 100644
--- a/Zend/zend.c
+++ b/Zend/zend.c
@@ -467,7 +467,7 @@ static void auto_global_copy_ctor(zval *zv) /* {{{ */
        zend_auto_global *old_ag = (zend_auto_global *) Z_PTR_P(zv);
        zend_auto_global *new_ag = pemalloc(sizeof(zend_auto_global), 1);

-       new_ag->name = old_ag->name;
+       new_ag->name = zend_string_dup(old_ag->name, 0);
        new_ag->auto_global_callback = old_ag->auto_global_callback;
        new_ag->jit = old_ag->jit;


It namely didn't crash on my side, but after some debugging valgrind showed issues. This seems pretty matching with the recent bug #71115.

Thanks.
 [2015-12-18 15:05 UTC] maroszek at gmx dot net
It seems to fix the segfault for Debian :)
But unfortunately this does not fix the problem on OS X. 

If you look at the error message:
<b>Fatal error</b>:  Maximum execution time of 30 seconds exceeded in <b>Unknown</b> on line <b>0</b><br />

This does seems more like a timing/signaling bug, doesn't it? The timeout should never be hit...

Do you have any chance to test this issue on OS X? Can i be of any further assistance?
 [2015-12-20 14:27 UTC] ab@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4c55669caa96f6202c2047a7baf6c5d5894d5fa7
Log: Partially fix bug #71129
 [2015-12-20 14:27 UTC] ab@php.net
-Status: Feedback +Status: Closed
 [2015-12-20 14:35 UTC] ab@php.net
-Status: Closed +Status: Feedback
 [2015-12-20 14:35 UTC] ab@php.net
@maroszek thanks for the check, a patch is now commited. I'm setting the status onto feedback as you have yet more issues.

Unfortunately I've no Mac to test it. But how it sounds like, the crash and the timeout issues are two separate things. As from your code, the requests should not be hanging but just running through, so no timeouts are expected. Though, as you've already said, Mac will use another threading library, so maybe it could condition the issue, but just a guess. You probably should debug through and check which request are not running through and why. Maybe there's a way to reproduce this on Linux as well. 

So set this to feedback, but i'd rather suggest to indeed close this one and to open another ticket for the exact timeout issue you experience. Please feel free to do so if you think it's ok.

Thanks.
 [2015-12-21 11:11 UTC] ab@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=53bfb6618d13083b769014cbdcb845f787a7cf28
Log: Revert &quot;Partially fix bug #71129&quot;
 [2015-12-21 11:11 UTC] ab@php.net
-Status: Feedback +Status: Closed
 [2015-12-21 11:31 UTC] ab@php.net
-Status: Closed +Status: Re-Opened
 [2015-12-21 11:52 UTC] maroszek at gmx dot net
I have seen that you have reverted the patch. Did you have any more information why it fails on OS X?

But I think my segfault does not relate to the other mentioned bug, because this one was already present in PHP 5.x. (AFAIK the other bug depends on the new PHP7 zend_strings ref count...)

My current theory:
Some timer does not behave corretly and falsely detects a script timeout. (the original bug) This leads to an invalid cleanup or a double free/double cleanup. 

Unfortunately valgrind under OS X does not detect any issues... drd/helgrind detects some issues, but i haven't validated those yet and as some of them are present in linux aswell so they might be just more false positives.
 [2015-12-21 12:20 UTC] ab@php.net
Hi,

yeah, reverted because i've seen there are some issues with CLI and it is definitely leaking in the main thread on any SAPI. Also this is not appropriate for the NTS builds. Have to do yet another round to collect all the cases, also in regard to #71115.

With the timeout - your code doesn't change the default ini, so it's 30 seconds. With an empty script that should never be the case, because the request should just run through and exit. But something blocks in the request, whether some lock or whatever, so then it hands 30 seconds and then gets bailed out. For Mac, there are for sure some native tools which possible would do a better job?

Thanks.
 [2015-12-21 13:02 UTC] maroszek at gmx dot net
Most often the request does not block but throws the error immediately. Therefore OS X might be *faster* somewhere and have a race condition, which checks for the timeout...
 [2015-12-25 20:04 UTC] maroszek at gmx dot net
-Operating System: OS X 11.11 +Operating System: OS X 10.11
 [2015-12-25 20:04 UTC] maroszek at gmx dot net
This really seems to be related to signaling, which seems to behave different on OS X. 

Disabling max_executing_time (or adding a simple return; in zend_bailout) seems to workaround the problem.

Line for the crash.cpp sample
> php_embed_module.ini_entries = "max_execution_time=0\n\0";

Do you know if the signal handler (zend_timeout) needs to be called in the same thread as the timed out script? (This does not seem to be the case for OS X)

There seems to be a known bug in SIGPROF on OS X, but as far as i have understood, it should be fixes for El Capitan and therefore not the problem in my case. (http://research.swtch.com/macpprof)
 [2016-01-11 17:33 UTC] ab@php.net
@maroszek With the segfault part, could you please check this patch? https://gist.github.com/weltling/e0922914dca8c8ee1886 If possible, please also test CLI and Apache. On my side, I was checking your embed implementation on windows and linux with TS/NTS CLI and Apache as well, none of those shows an issue.

With the timeout part - i guess that your theory is not correct. What the while(true) loop does is constantly processing the requests with the empty.php file. There is per se neither timeout, nor any signal expected. It might be a race condition that block a request, so then it gets signaled after 30 seconds. I've got no OSX to investigate on this :( I guess there have to be some native OSX tools for such cases. What I could also imagine that it could also be some OS specific issue with the threading library, maybe if you explicitly link pthreads on OSX, it'll differ? 

Thanks.
 [2016-02-16 15:16 UTC] ab@php.net
@maroszek, ping :) Were you able to test the patch i've linked in the previous post?

Thanks.
 [2016-02-17 14:30 UTC] maroszek at gmx dot net
Last time i tried, the segfauls weren't happening with this patch on OSX (the other error remains). I can give it another try in the few days. Though i can only check the embed part.
 [2016-07-20 11:34 UTC] davey@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=53bfb6618d13083b769014cbdcb845f787a7cf28
Log: Revert &quot;Partially fix bug #71129&quot;
 [2016-07-20 11:34 UTC] davey@php.net
-Status: Re-Opened +Status: Closed
 [2016-07-20 11:34 UTC] davey@php.net
Automatic comment on behalf of ab
Revision: http://git.php.net/?p=php-src.git;a=commit;h=4c55669caa96f6202c2047a7baf6c5d5894d5fa7
Log: Partially fix bug #71129
 [2016-07-21 07:24 UTC] davey@php.net
-Status: Closed +Status: Re-Opened
 [2016-07-21 07:24 UTC] davey@php.net
Closed accidentally. Reopening.
 [2017-01-16 16:26 UTC] ejrx7753 at gmail dot com
I have tested the code sample (https://gist.github.com/paresy/b4babb919a86e9764bc4) with OS X 10.12 and PHP 7.1.0, built with embed as a static library.

I posted previously another bug report (https://bugs.php.net/bug.php?id=73826) which might contain some useful information because I was able to get ZTS working by a number of somewhat random steps. To give a short summary, "php_embed_init" function works, but "php_embed_module.startup" doesn't. It appears therefore to be some kind of initialization process problem.

I tried "php_embed_module.ini_entries = "max_execution_time=0\n\0";" as mentioned in this thread, but with a seg fault.
 [2017-01-16 16:27 UTC] ejrx7753 at gmail dot com
I forgot to write the result -> "I tested the code sample" and found that it still segfaults.
 [2017-01-16 16:43 UTC] ejrx7753 at gmail dot com
Confirmed that using the code

    int argc2 = 1;
    char* text = "embed4";
    char *argv2[2] = { text, NULL };
    php_embed_init(argc2, argv2);

to replace sapi_startup and php_embed_module.startup and deleting the "php_embed_module" struct (duplicate symbol error) allows the code to work.

I have created a sample file which can test both versions (http://pastebin.com/8sHjP9Jy).

When run with

#define TEST1 0

the test fails, but when run with

#define TEST1 1

it passses. In my case, the script was "echo 1" and proceeded to give an infinite loop of 1s to the std out. The question also needs addressing whether or not we can set the embed module elements and use embed init. I think so, but it is another difference between the code peices.
 [2017-01-16 22:06 UTC] ejrx7753 at gmail dot com
Looking through the "php_embed_init" function, it is more or less exactly the same as the code provided, with the clear exception of a few signalling changes.

In particular,

signal(SIGPIPE, SIG_IGN);

and

zend_signal_startup();

A minor difference is the code

  (void)ts_resource(0);
  ZEND_TSRMLS_CACHE_UPDATE();

and a malloc on ini_entries.

Does this not suggest that the embed module should get its own initializer, ie. php_embed_init(&php_embed_module) to init the signals, or that embed_init() [no args} should be created to run before sapi startup to call the private signalling code and whatever other steps will arise?
 [2017-01-16 23:01 UTC] ejrx7753 at gmail dot com
Adding the lines

    php_embed_module.ub_write = php_embed_ub_write;
    php_embed_module.flush = php_embed_flush;

after

php_embed_init

works so long as nothing is done with the output. Uncommenting "std::cout << str;" inside of php_embed_ub_write causes a segmentation fault "pointer being freed was not allocated" reliably inside the shutdown executor.
 [2017-01-20 14:08 UTC] maroszek at gmx dot net
I updated the code for PHP 7.1.1. The issue remains.

Gist: https://gist.github.com/paresy/b4babb919a86e9764bc4
Needed fix: https://bugs.php.net/bug.php?id=71041
Build: g++ crash.cpp -Imain -ITSRM -IZend -I. --std=c++11 -Llibs -lphp7 -lxml2 -lresolv -ldl -pthread -fpermissive
Run: ./a.out

Crash:
(gdb) bt
#0  zend_mm_free_heap (ptr=0xf3c080, heap=0x7fffe9600040)
    at /home/user/Downloads/php-7.1.1/Zend/zend_alloc.c:1374
#1  _efree (ptr=0xf3c080)
    at /home/user/Downloads/php-7.1.1/Zend/zend_alloc.c:2433
#2  0x0000000000490405 in zend_string_release (s=<optimized out>)
    at /home/user/Downloads/php-7.1.1/Zend/zend_string.h:272
#3  _zend_hash_del_el_ex (prev=<optimized out>, p=<optimized out>, 
    idx=<optimized out>, ht=<optimized out>)
    at /home/user/Downloads/php-7.1.1/Zend/zend_hash.c:992
#4  _zend_hash_del_el (p=0x7fffe9656120, idx=1, ht=0x7fffc8025140)
    at /home/user/Downloads/php-7.1.1/Zend/zend_hash.c:1021
#5  zend_hash_graceful_reverse_destroy (ht=0x7fffc8025140)
    at /home/user/Downloads/php-7.1.1/Zend/zend_hash.c:1477
#6  0x000000000046c1f5 in shutdown_executor ()
    at /home/user/Downloads/php-7.1.1/Zend/zend_execute_API.c:279
#7  0x000000000047daab in zend_deactivate ()
    at /home/user/Downloads/php-7.1.1/Zend/zend.c:997
#8  0x0000000000417fe9 in php_request_shutdown (dummy=<optimized out>)
    at /home/user/Downloads/php-7.1.1/main/main.c:1877
#9  0x0000000000414364 in main::{lambda()#1}::operator()() const ()
#10 0x000000000041548c in void std::_Bind_simple<main::{lambda()#1} ()>::_M_invoke<>(std::_Index_tuple<>) ()
#11 0x00000000004153e2 in std::_Bind_simple<main::{lambda()#1} ()>::operator()() ()
#12 0x0000000000415372 in std::thread::_Impl<std::_Bind_simple<main::{lambda()#1} ()> >::_M_run() ()
#13 0x00007ffff7331930 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#14 0x00007ffff6b406ba in start_thread (arg=0x7fffeb7fe700)
    at pthread_create.c:333

Thanks for any hints on the issue!
 [2017-01-20 14:09 UTC] maroszek at gmx dot net
I forgot to mention that this issue is also available on Linux (Ubuntu 16.04)
 [2017-01-20 14:17 UTC] maroszek at gmx dot net
@ab:  I've somehow missed that you already proposed a patch. After applying it everything looks fine on my linux box. Any chance to get this merged?

Thank!
 [2017-01-20 21:50 UTC] ejrx7753 at gmail dot com
@maroszek

Your gist includes signal_startup (https://gist.github.com/paresy/b4babb919a86e9764bc4) and you give a negative result (no confirmation of the test that I posted either), but on https://bugs.php.net/bug.php?id=71041 you confirm that the signal_startup is the issue. Did you forget to post some details?

Concerning your post there, it seems to me that running php_embed_init is an acceptable solution instead of sapi_startup. I don't see yet any deficiency with it.
 [2017-03-29 12:12 UTC] ab@php.net
-Status: Re-Opened +Status: Feedback
 [2017-03-29 12:12 UTC] ab@php.net
Please try using this snapshot:

  http://snaps.php.net/php-trunk-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/

See also #74011.
 [2017-04-06 10:15 UTC] maroszek at gmx dot net
Thanks! We can close this one :)
 [2017-04-09 04:22 UTC] php-bugs at lists dot php dot net
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Re-Opened". Thank you.
 
PHP Copyright © 2001-2022 The PHP Group
All rights reserved.
Last updated: Mon Aug 15 01:05:44 2022 UTC