You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
OPCache with Enum and Callback functions results in segmentation fault #10914
<?phpfunctionauxiliarFunction(string$enumEntry) {}
functiontriggerException(callable$callback) {
$callback();
}
functionmain() {
triggerException(function () {
auxiliarFunction(ExampleEnum::FIRST->value); //This will not run and trigger a SIGSEGV - core dumped
});
}
This was first spotted on Symfony 5.4 codebase, with a callback of the TagAwareCacheInterface.
If OPCache is disabled, the error doesn't occur.
Replacing the enum with a string variable fixes the issue.
PHP Version
PHP 8.1.11 (fpm-fcgi)
Operating System
Ubuntu 20.04.5 LTS
Reacted by Ilija Tovilo, Baptiste Lafontaine and Benjamin Dos Santos
We also found out that ExampleEnum::cases() passed with the function () use (), also causes a segmentation fault.
$cases = ExampleEnum::cases();
triggerException(function () use ($cases) {
auxiliarFunction($cases); //This will not run and trigger a SIGSEGV - core dumped
});
I've been unable to reproduce this so far. I tested this without Symfony though, just with the two provided files.
Are you using the JIT or not? If you're using the JIT, does it also reproduce without?
What extensions did you use when you could reproduce this?
Does this always reproduce reliably?
If needed I can create a docker with a symfony project that recreates this issue.
After that any access to the enum inside the callback used by redis cache function will throw segsev
I wasn't able to recreate a docker instance with it.
I believe I setup the core dump correctly here is the link (size: 349MB): <snip, removed coredump file>
Gets weirder in every debug, I am able to duplicate it constantly on our codebase but I am not allowed to share it...
Might be an issue with Symfony, or the redis, but xdebug dies on the Enum::cases or Enum::Entry->value.
Thanks. It's definitely not a JIT issue because that's disabled. Since you mention this happens with redis, this makes me wonder if it's an issue with that extension instead of PHP itself.
I assume you're using https://github.com/phpredis/phpredis ?
I can open the coredump with a multiarch gdb build, but can't do much because I'm on x86 instead of ARM.
Is it possible to load the coredump on the machine it was generated on and run the gdb command: bt full ?
I am able to do bt full on a similar machine (machine that generate it is already terminated, build image is the same)
We are using predis and not PHPRedis.
If you need any more info from me, please guide me as my knowledge of gdb is far lost.
For more details on the machine we use a AWS c6g.large, with Ubuntu 20.04.5 ARM base image, nothing was compiled from source, all installed from ppa:ondrej/php
The Redis server is ElastiCache Redis, and we made sure the server had sufficient RAM and CPU to handle the requests.
I'm not sure if I actually explained the previous instructions properly.
Can you please share the output of bt full in gdb with your core dump loaded? I don't have access to an ARM machine and so I can't do much on my system with the coredump you provided.
To load the core dump you can use gdb path/to/binary path/to/coredump. Then you can type in the bt full command.
@iluuu1994 Yeah I also found that. I just wasn't sure about the overhead but if this is the general approach I'll go with that.
I'm checking all code now.
@nielsdos Class constants should only be evaluated once. If we copy the constant AST and evaluate it then, we'll lose the value and evaluate it again on the next access. I think, for enum cases this would mean getting non-unique case values. So I don't think we have another option.
Activity
miguelantoniosantos commentedon Mar 23, 2023
We also found out that ExampleEnum::cases() passed with the function () use (), also causes a segmentation fault.
We mitigated the issue with
If needed I can create a docker with a symfony project that recreates this issue.
ndossche commentedon Mar 23, 2023
I've been unable to reproduce this so far. I tested this without Symfony though, just with the two provided files.
Are you using the JIT or not? If you're using the JIT, does it also reproduce without?
What extensions did you use when you could reproduce this?
Does this always reproduce reliably?
This would be very helpful!
Alternatively, are you able to provide a backtrace from GDB?
To find out how to generate a backtrace, please read http://bugs.php.net/bugs-generating-backtrace.php for Linux/macos and http://bugs.php.net/bugs-generating-backtrace-win32.php for Windows.
miguelantoniosantos commentedon Mar 24, 2023
We are able to recreate this with a 100% crash rate.
I will fetch the php -i details; backtrace and recreate the issue with docker.
I expect to have this ready at max in 7 days, will try today but I can't guarantee it
miguelantoniosantos commentedon Mar 24, 2023
After some debugging it seems like this:
I wasn't able to recreate a docker instance with it.
I believe I setup the core dump correctly here is the link (size: 349MB): <snip, removed coredump file>
Gets weirder in every debug, I am able to duplicate it constantly on our codebase but I am not allowed to share it...
Might be an issue with Symfony, or the redis, but xdebug dies on the Enum::cases or Enum::Entry->value.
PHP Ini: https://gist.github.com/miguelantoniosantos/200ebb03dbc1996cbbc6c7edc8510d18
ndossche commentedon Mar 24, 2023
Thanks. It's definitely not a JIT issue because that's disabled. Since you mention this happens with redis, this makes me wonder if it's an issue with that extension instead of PHP itself.
I assume you're using https://github.com/phpredis/phpredis ?
I can open the coredump with a multiarch gdb build, but can't do much because I'm on x86 instead of ARM.
Is it possible to load the coredump on the machine it was generated on and run the gdb command:
bt full?miguelantoniosantos commentedon Mar 24, 2023
I am able to do
bt fullon a similar machine (machine that generate it is already terminated, build image is the same)We are using predis and not PHPRedis.
If you need any more info from me, please guide me as my knowledge of gdb is far lost.
ndossche commentedon Mar 24, 2023
Interesting how it's not a PECL extension causing the issue.
bt fullon a similar machine is probably fine too as their image is the same.miguelantoniosantos commentedon Mar 24, 2023
For more details on the machine we use a AWS c6g.large, with Ubuntu 20.04.5 ARM base image, nothing was compiled from source, all installed from
ppa:ondrej/phpThe Redis server is ElastiCache Redis, and we made sure the server had sufficient RAM and CPU to handle the requests.
ndossche commentedon Mar 24, 2023
I'm not sure if I actually explained the previous instructions properly.
Can you please share the output of
bt fullin gdb with your core dump loaded? I don't have access to an ARM machine and so I can't do much on my system with the coredump you provided.To load the core dump you can use
gdb path/to/binary path/to/coredump. Then you can type in thebt fullcommand.23 remaining items
ndossche commentedon Jul 11, 2023
With protect_memory enabled, this is the minimal reproducer, which will crash instantly if enum.php is preloaded:
No need to externals dependencies.
The external dependencies just created the "lucky" heap layout that made it able to hit the issue without protect_memory.
iluuu1994 commentedon Jul 11, 2023
@nielsdos I haven't tried it, but I think this line needs to be fixed:
php-src/ext/reflection/php_reflection.c
Line 6895 in c1d4d95
We're accessing the class constants directly, instead of using
CE_CONSTANTS_TABLE(ce), which separates the table if it contains constant ASTs.Thank you a lot for the analysis!
Edit: And it looks like
getCasewill have the same issue.ndossche commentedon Jul 11, 2023
@iluuu1994 Yeah I also found that. I just wasn't sure about the overhead but if this is the general approach I'll go with that.
I'm checking all code now.
iluuu1994 commentedon Jul 11, 2023
@nielsdos Class constants should only be evaluated once. If we copy the constant AST and evaluate it then, we'll lose the value and evaluate it again on the next access. I think, for enum cases this would mean getting non-unique case values. So I don't think we have another option.
ndossche commentedon Jul 11, 2023
Both seemed to work so thanks for your explanation on why we need separation. I'll fix it using the separation.
iluuu1994 commentedon Jul 11, 2023
Thank you a lot @nielsdos!
Fix phpGH-10914: OPCache with Enum and Callback functions results in …
magnetik commentedon Jul 11, 2023
Awesome @nielsdos ! Thanks for the fix. looking forward to have it :)
Fix GH-10914: OPCache with Enum and Callback functions results in seg…
Merge branch 'PHP-8.1' into PHP-8.2
Merge branch 'PHP-8.2'