Bug #75351 [Fbk->NoF]: Segmentation fault on fatal error during Generator::send
| From: | php-bugs at lists dot php dot net | 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