A ssegmentation fault in PHP is often the cause of a PHP extensions written in C, and more specifically one with a memory management error. However, I have encountered my share of segfaults during network programming, but I pair these with PHP's pthreads extension, so it would explain why. It is also possible to encounter segfaults from infinite recursion, but the root cause is still more or less the same - something weird in memory management.
Below I compile with -g
flag to enable PHP's GD extension, -t linux64
because I am running on a Ubuntu server, and -P5
to install PM5's dependencies and the right versions for those dependencies.
YMMY. See PHP-Binaries for more flags and info.
git clone https://github.com/pmmp/PHP-Binaries.git
cd PHP-Binaries
./compile.sh -g -d -n -t linux64 -j4 -P5
Run gdb
against the PHP executable from the above step. Then run
PocketMine in GDB.
If you are running PocketMine from source, you would run ./src/PocketMine.php
instead.
gdb /path/to/PHP-Binaries/bin/php7/bin/php
(gdb) run ./PocketMine-MP.phar
Your PocketMine server should be running as normal. It may be a little slow because the debugger causes some noise, but it should still run at an acceptable CPU load.
Boring part. Now we wait for the segfault to happen. If you can cause the segfault at will, good for you - go ahead and do that right now.
DO NOT EXIT GDB once the segfault happens - there is still a step 3!
source
here loads the .gdbinit
file that defines the command zbacktrace
which generates a readable backtrace.
(gdb) source /path/to/PHP-Binaries/install_data/subdir/php/.gdbinit
(gdb) zbacktrace
[0x7f8809026350] Ds\Set->contains(object[0x7f88090263a0]) [internal function]
[0x7f86f3271b00] cosmicpe\item\enchantment\utils\EnchantmentUtils->getNearbyEntities(object[0x7f86f3271b50], 2025.000000, array(0)[0x7f86f3271b70], reference)
phar:///home/cosmicpe/void/plugins/CosmicPE_v0.0.2.phar/src/cosmicpe/item/enchantment/utils/EnchantmentUtils.php:143
In my case, the cause was the php-ds extension's Set implementation doing something unpleasant. Not only can I infer that from the backtrace, I also know the Set::contains() call responsible for it.
You may run exit
inside GDB when you are done.