php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74157 Segfault with nested generators
Submitted: 2017-02-23 20:17 UTC Modified: 2017-02-25 04:26 UTC
From: tom at inflatablecookie dot com Assigned: dmitry
Status: Closed Package: Reproducible crash
PHP Version: 7.1.2 OS: OSX Sierra 10.12.3
Private report: No CVE-ID:
 [2017-02-23 20:17 UTC] tom at inflatablecookie dot com
Description:
------------
Upgrading to 7.1.2 has introduced a regular segfault when using nested generators - I'm assuming it was introduced with the following from the changelog:

-Improved GENERATOR_CREATE opcode handler.

This happens regardless of platform (tested on OSX Sierra and Ubuntu), and regardless of extensions enabled (still occurs with all available extensions disabled).

As of now, I'm struggling to come up with a decent test script as the real-world scenario leverages a significant amount of user code, however the segfault always occurs upon entry to a generator function called after a certain number of nested generators have successfully run. I'll update once I can replicate in a simple test environment.

The basic premise of the code is to generate html tags - the tag object takes a generator as argument which yields string or object contents, which generally includes more tag objects with their own generator, etc.

Actual result:
--------------
Here's the backtrace (from OSX console)

0   0x000000010754cb01 zend_generator_close + 326
1   0x00000001075a9e90 ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER + 51
2   0x0000000107561d3e execute_ex + 44
3   0x000000010754d3b5 zend_generator_resume + 377
4   0x000000010757e877 ZEND_FE_FETCH_R_SPEC_VAR_HANDLER + 346
5   0x0000000107561d3e execute_ex + 44
6   0x00000001075157d4 zend_call_function + 1468
7   0x000000010753f7ad zend_call_method + 581
8   0x000000010755a3b7 zend_std_cast_object_tostring + 314
9   0x000000010751acb1 _zval_get_string_func + 381
10  0x00000001075724e0 ZEND_ECHO_SPEC_TMPVAR_HANDLER + 69
11  0x0000000107561d3e execute_ex + 44
12  0x0000000107561fb6 zend_execute + 551
13  0x0000000107523e94 zend_execute_scripts + 299
14  0x00000001074cb7e8 php_execute_script + 804
15  0x00000001075c9582 main + 6286
16  0x00007fff98117255 start + 1

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-02-24 06:57 UTC] laruence@php.net
-Status: Open +Status: Feedback
 [2017-02-24 06:57 UTC] laruence@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.


 [2017-02-24 17:59 UTC] tom at inflatablecookie dot com
-Status: Feedback +Status: Open -Package: opcache +Package: Reproducible crash
 [2017-02-24 17:59 UTC] tom at inflatablecookie dot com
Ok, this is quite an obscure bug to diagnose and isolate, and involves interaction between nested helper objects and nested generators.

I have managed to strip it down to an example script of about 70 lines (I can't get it any smaller than that though) - http://pastebin.com/NRSUNvF8

This script consistently causes segfault on both OSX (homebrew) and ubuntu (ondrej ppa) with PHP 7.1.2 and all extensions turned off (using php -n test.php).

The critical code is the block of yield statements between lines 12 and 16; it is specifically the use of the helper objects, notably via the wrapped __call() -> __invoke() and direct method calls, plus the use() clause on the generator to bring in template data, all in concert that cause the error. Removing any of these elements causes the error to either stop completely or only show intermittently. Both helpers are required to generate the fault, using only one generally results in the script completing.

It seems like a predetermined memory allocation is either overflowing or prematurely released for the references to the helper objects and data, but this is just speculation. Either way, it's a critical show-stopper for us as we use this pattern extensively, we've had to revert to 7.0 syntax and distribution for now - any help is very much appreciated!
 [2017-02-25 04:26 UTC] laruence@php.net
-Status: Open +Status: Verified -Assigned To: +Assigned To: dmitry
 [2017-02-25 04:26 UTC] laruence@php.net
yeah, I can confirm this is caused by https://github.com/php/php-src/commit/9a159f37

@dmitry, I think this line below is suspicious. :

+ if (EXPECTED(num_args <= EX(func)->op_array.last_var)) {

as I understand this line should be:

+ if (EXPECTED(num_args <= EX(func)->op_array.num_args)) {


can you verify this?

thanks
 [2017-02-26 04:08 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6a584cf318a9265a55df69930a64122fcde46948
Log: Fixed bug #74157 (Segfault with nested generators)
 [2017-02-26 04:08 UTC] laruence@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Aug 29 15:01:52 2017 UTC