Bug #75351 [Fbk->NoF]: Segmentation fault on fatal error during Generator::send

From: Date: Sun, 24 Jun 2018 04:25:33 +0000
Subject: Bug #75351 [Fbk->NoF]: Segmentation fault on fatal error during Generator::send
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-215914@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=75351&edit=1 ID: 75351 Updated by: php-bugs@lists.php.net Reported by: bashofmann at gmail dot com Summary: Segmentation fault on fatal error during Generator::send -Status: Feedback +Status: No Feedback Type: Bug Package: Scripting Engine problem Operating System: Ubuntu 14.04.5 LTS (GNU/Linux 4. PHP Version: 7.1.10 Private report: N New Comment: 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. Previous Comments: ------------------------------------------------------------------------ [2018-01-13 10:12:39] nikic@php.net I've applied another fix for the last issue I mentioned: https://github.com/php/php-src/commit/8c07170ddbe28d8cc31e71f0ceb94fc4ac329657 ------------------------------------------------------------------------ [2018-01-12 21:59:07] nikic@php.net I've applied https://github.com/php/php-src/commit/cab0a814bdbfc653754f74b42056c38bdf4fbadb, which fixes some crashes of the type described here I was able to produce under artificial GC configurations. Please check whether current 7.1/7.2/master snapshots resolve the issue for you. I think there is still a lingering problem here, because root and parent references are not necessarily consistent, in that root references might point deeper into the tree than the parent chain under some circumstances. However, I'm not sure if checking for null is the right answer for that (as I think this might miss the generators that are between the root reference and the end of the parent chain) or whether we should be using a reverse loop from root to leaf as we do in most other places. ------------------------------------------------------------------------ [2018-01-09 14:36:46] daniel dot tschinder at researchgate dot net Did anyone of you find a workaround? We have the same problem, but I cannot really figure out how to workaround and it does not happen every time. I once managed to debug when this happened, but all I saw was that the process died on Generator::send. ------------------------------------------------------------------------ [2017-12-11 23:31:38] tandre@php.net A workaround I'm considering is to call Generator->next(), since my code was already always calling send with NULL. The implementation Generator->send() calls zend_generator_get_current(), but Generator->next() does not. ------------------------------------------------------------------------ [2017-12-11 22:18:03] tandre@php.net I'm encountering similar issues, also in Generator->send(). However, the issues I see are in zend_generator_get_gc instead It seems like garbage collection is getting triggered when Generator->send() is getting called, which may be an edge case that isn't handled properly, and may be related to why it's hard to reproduce. I'm using $retval = yield from, $retval = yield some_helper(), yield other_helper() in the code in question, but the bug happens so infrequently I'm not sure which part it is. I haven't checked how deeply nested yields are. I'm using PHP 7.1.9. The source of zend_generators.c is identical for 7.1.9 and 7.1.12 (latest). Stack trace: ``` ... Lines added by newrelic segfault stack trace dumper omitted /usr/local/php/modules/libphp7.so(+0x431748)[0x7ff795959748] /usr/local/php/modules/libphp7.so(+0x42d4fa)[0x7ff7959554fa] /usr/local/php/modules/libphp7.so(zend_gc_collect_cycles+0x78)[0x7ff795956478] /usr/local/php/modules/libphp7.so(gc_possible_root+0x9e)[0x7ff7959560ee] /usr/local/php/modules/libphp7.so(+0x43220c)[0x7ff79595a20c] /usr/local/php/modules/libphp7.so(zend_objects_store_del+0x271)[0x7ff79596c231] /usr/local/php/modules/libphp7.so(zend_generator_update_current+0x1f0)[0x7ff79595a9b0] /usr/local/php/modules/libphp7.so(zend_generator_resume+0x1dd)[0x7ff79595a4ad] /usr/local/php/modules/libphp7.so(+0x433bdf)[0x7ff79595bbdf] /usr/local/php/modules/libphp7.so(+0x4b70c6)[0x7ff7959df0c6] /usr/local/php/modules/libphp7.so(execute_ex+0x2b)[0x7ff79597738b] /usr/local/php/lib/php/20160303/newrelic.so(+0x231bb)[0x7ff78b0b61bb] /usr/local/php/lib/php/20160303/newrelic.so(+0x23802)[0x7ff78b0b6802] /usr/local/php/modules/libphp7.so(+0x4b6985)[0x7ff7959de985] /usr/local/php/modules/libphp7.so(execute_ex+0x2b)[0x7ff79597738b] /usr/local/php/lib/php/20160303/newrelic.so(+0x231bb)[0x7ff78b0b61bb] /usr/local/php/lib/php/20160303/newrelic.so(+0x23802)[0x7ff78b0b6802] ``` I added comments to parts of the code that showed up in my stack trace, and ``` --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -275,7 +275,7 @@ static uint32_t calc_gc_buffer_size(zend_generator *generator) /* {{{ */ /* Yield from root references */ if (generator->node.children == 0) { zend_generator *child = generator, *root = generator->node.ptr.root; - while (root != child) { + while (root != child && child != NULL) { // Not sure if checking for null would solve the underlying issue for the other bug reported, and I'm not familiar with how deep the chain goes. child = child->node.parent; size++; } @@ -340,8 +340,8 @@ static HashTable *zend_generator_get_gc(zval *object, zval **table, int *n) /* { if (generator->node.children == 0) { zend_generator *child = generator, *root = generator->node.ptr.root; - while (root != child) { - child = child->node.parent; + while (root != child && child != NULL) { // Not sure if checking for null would solve the underlying issue + child = child->node.parent; // child->node is somehow equal to null when the segfault occurs ZVAL_OBJ(gc_buffer++, &child->std); } } @@ -608,7 +608,7 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator } while (!root->execute_data && root != generator) { - OBJ_RELEASE(&old_root->std); + OBJ_RELEASE(&old_root->std); // Not caused by this OBJ_RELEASE. It's caused by the below one. old_root = root; root = zend_generator_get_child(&root->node, leaf); @@ -638,10 +638,11 @@ ZEND_API zend_generator *zend_generator_update_current(zend_generator *generator EG(current_execute_data) = original_execute_data; if (!((old_root ? old_root : generator)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING)) { - leaf->node.ptr.root = root; - root->node.parent = NULL; + leaf->node.ptr.root = root; // The root pointer and root->node pointer were changed. + root->node.parent = NULL; // And a parent gets set to null, which might interfere with zend_generator_get_gc + // What happens if there are nested yield froms, though? Would those still have (something)->node.ptr.root point to old_root? if (old_root) { - OBJ_RELEASE(&old_root->std); + OBJ_RELEASE(&old_root->std); // Disassembly shows that this triggers a garbage collection } zend_generator_resume(leaf); return leaf->node.ptr.root; /* this may be updated during zend_generator_resume! */ ``` ------------------------------------------------------------------------ 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=75351 -- Edit this bug report at https://bugs.php.net/bug.php?id=75351&edit=1

« previous php.bugs (#215914) next »