-
-
Notifications
You must be signed in to change notification settings - Fork 251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: superglobals-realated crash with custom extensions in worker mode #796
Conversation
8b8753c
to
edee8bb
Compare
@withinboredom @TimWolla would you mind reviewing the proposed fix? I need to do more testing to ensure that the behavior is what is expected, but at least this fixes the segfault. We'll have to double-check if this doesn't introduce a memory leak or some weird issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to do more testing to ensure that the behavior is what is expected, but at least this fixes the segfault. We'll have to double-check if this doesn't introduce a memory leak or some weird issues.
It does leak:
[Tue May 21 07:27:50 2024] Script: '-'
/usr/local/src/php/Zend/zend_string.h(174) : Freeing 0x00007fff802020a0 (40 bytes), script=-
Last leak repeated 14 times
[Tue May 21 07:27:50 2024] Script: '-'
/usr/local/src/php/Zend/zend_string.h(174) : Freeing 0x00007fff802020f0 (40 bytes), script=-
Last leak repeated 42 times
[Tue May 21 07:27:50 2024] Script: '-'
/usr/local/src/php/Zend/zend_string.h(174) : Freeing 0x00007fff802025a0 (40 bytes), script=-
Last leak repeated 12 times
[Tue May 21 07:27:50 2024] Script: '-'
/usr/local/src/php/Zend/zend_hash.c(291) : Freeing 0x00007fff8025f000 (56 bytes), script=-
Last leak repeated 4 times
[Tue May 21 07:27:50 2024] Script: '-'
/usr/local/src/php/Zend/zend_hash.c(1311) : Freeing 0x00007fff80260c00 (2560 bytes), script=-
=== Total 77 memory leaks detected ===
For debugging memory leaks, I suggest USE_ZEND_ALLOC=0
+ ASAN. Valgrind does not appear to work well here.
I'm also seeing
2024/05/21 07:27:50.165 INFO restarting {"worker": "/go/src/app/testdata/worker.php"}
immediately after, but I'm not sure if that is expected.
The following test script also appears to log the incorrect information:
<?php
ignore_user_abort(true);
for($running = true; $running;) {
file_put_contents(__DIR__ . '/log', "before: " . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND);
$running = \frankenphp_handle_request(static function () {
file_put_contents(__DIR__ . '/log', "inside: " . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND);
});
file_put_contents(__DIR__ . '/log', "after : " . $_SERVER['REQUEST_URI'] . ' ' . $_SERVER['REMOTE_ADDR'] . "\n", FILE_APPEND);
}
I would expected before:
and after:
to look identical at all times, but I'm seeing:
before: worker.php
before: worker.php
before: worker.php
before: worker.php
inside: /worker.php?some_query_parameters 127.0.0.1
after : /worker.php?some_query_parameters 127.0.0.1
before: /worker.php?some_query_parameters 127.0.0.1
inside: /worker.php?some_query_parameters 127.0.0.1
after : /worker.php?some_query_parameters 127.0.0.1
before: /worker.php?some_query_parameters 127.0.0.1
I does point out some conditional jumps that depend on uninitialized in non-go code values, though. But also quite a few invalid reads in go code, which might or might not be expected. |
The cause probably is that you can't naively |
Thanks for your detailed review @TimWolla. Regarding the Docker container, it is entirely optional. When you have a local installation of PHP, you can just run this command to compile the binary: https://frankenphp.dev/docs/compile/#compile-the-go-app |
I pushed a new version that uses This behaves almost as expected but I identified two issues:
|
The behavior is now the expected one. If you don't mind, cloud you please review again? |
Actually, merging the $_SERVER superglobals of the worker and the request wasn't expected, we even have a test (the failing one) for that. As showcased by the test, it's entirely possible to do that userland if needed. Should we keep the existing behavior of not merging (after a second thought, I think that it's more flexible to not merge)? |
I'm still seeing a leak:
and then calling I also might've done something wrong while starting FrankenPHP, because of the |
And the test script with the |
I've an idea for the |
Maybe related: #81 |
@TimWolla @withinboredom would you mind testing/reviewing this patch one more time? The current implementation looks ok-ish to me. |
@dunglas For the test script in #796 (review) I'm still seeing the wrong data being written to the
|
In the last commit, I fixed the crash without changing the existing behavior (the docs change is now irrelevant, I'll revert that). I think it's good enough for now. |
I can confirm the crash is fixed, but internal functions see an empty |
return 0; | ||
} | ||
|
||
free(ctx->cookie_data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving this free()
here likely fixes a memory leak in worker mode.
I cleaned the code and updated the docs. I think I've found a way to keep the userland and internal structures in sync but I didn't create a test case. @TimWolla would you mind checking if this now works with the Tideways extension? |
I can confirm that internal functions called after However what is not kept in sync is manually writing to $_SERVER['dummy'] = 'value'; Dumping ZEND_FUNCTION(native_debug)
{
zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
HashTable *server = Z_ARRVAL_P(&PG(http_globals)[TRACK_VARS_SERVER]);
printf("%d\n", zend_hash_num_elements(server));
zval *request_uri = zend_hash_str_find(server, "REQUEST_URI", strlen("REQUEST_URI"));
printf("%s\n", Z_STRVAL_P(request_uri));
} prints 41 (because $_SERVER['REQUEST_URI'] = 'dummy'; is not visible to the native function. I'm not sure if as a user I would prefer a crash or silently incorrect data. Your call. |
@TimWolla are the two data structures synced automatically in a normal script? I may be wrong, but I don't think that we do anything special FrankenPHP-side that would cause this desync. |
@TimWolla according to my tests, this behaves the same even when not in worker mode, so it looks "expected" to me, at least let's say that it's not related to FrankenPHP. |
@dunglas Can confirm with the cli-server. Sorry for the confusion. This looks good to me then! |
Closes #767.
Partial fix for #592 (memory leak when dealing with cookies in worker mode).