Slide 1

Slide 1 text

How to Debug Bizarre PHP Bugs Photo by Dmitry Bukhantsov

Slide 2

Slide 2 text

Kévin Dunglas ➔ Co-founder of Les-Tilleuls.coop ➔ Creator of FrankenPHP and API Platform ➔ Co-maintainer of Caddy and Symfony ➔ Contributor to PHP, and by necessity, to Xdebug 🐞 @dunglas

Slide 3

Slide 3 text

PHP, Web and Cloud Experts ➔ Development: PHP, JS, Go, Rust, C... ➔ DevOps and SRE ➔ Consultancy and maintenance ➔ Agile management, UX and UI design… ➔ [email protected] 💌

Slide 4

Slide 4 text

Where's the Bug?

Slide 5

Slide 5 text

As a user: is the bug in my code or in the library I'm using? There might be a bug in the lib (but could be in your code) The bug is probably in your code (but could be in the lib) Is this lib popular? Has a new version been published recently? Does downgrading solve this issue? Are you using the lib in a weird or advanced way? Have others users reported this bug? YES NO YES NO YES NO YES NO NO YES

Slide 6

Slide 6 text

As a maintainer: is the bug in my lib or in user’s code? The bug is likely in their code It is a regular contributor? How many users reported the bug? SOME MANY A SINGLE USER NO YES

Slide 7

Slide 7 text

Bizarre Bugs!

Slide 8

Slide 8 text

A bizarre bug

Slide 9

Slide 9 text

More Bizarre Bugs

Slide 10

Slide 10 text

🔥🔥

Slide 11

Slide 11 text

Reminder The bug is likely in their code It is a regular contributor? How many users reported the bug? SOME MANY A SINGLE USER NO YES W e’re here!

Slide 12

Slide 12 text

But What Is Xdebug Anyway?

Slide 13

Slide 13 text

A must-have for PHP development: ➔ Step debugging ➔ Better error reporting ➔ Function calls tracing ➔ Profiling ➔ Code coverage ➔ Installed by default with Symfony Docker, API Platform and Laravel Herd ➔ Supported by PhpStorm, VSCode and (Neo)vim Xdebug

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

Asking For Help

Slide 17

Slide 17 text

Let’s Try To Find the Issue Together!

Slide 18

Slide 18 text

Step 1: Reproducing

Slide 19

Slide 19 text

A Minimal Reproducer

Slide 20

Slide 20 text

Step 2: Gathering Information

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

➔ Debug symbols ● Make stack traces readable ● Available as extra packages for some (but not all) distributions ○ Debian: "How To Get A Backtrace" ● Not available (yet?) for official Docker images: docker-library/php#1538 ➔ The GNU Debugger (or lldb on Mac) Let Me Introduce You To:

Slide 23

Slide 23 text

My Reco: Compile PHP with Debug Symbols From Source gh repo clone php/php-src cd php-src/ ./buildconf -f ./configure \ --enable-embed \ --enable-zts \ --disable-zend-signals \ --enable-debug make sudo make install

Slide 24

Slide 24 text

Compile FrankenPHP to Use Our libphp gh repo clone dunglas/frankenphp cd frankenphp/caddy/frankenphp export PATH="/usr/local/bin/:$PATH" export CGO_CFLAGS=$(php-config --includes) export CGO_LDFLAGS="$(php-config --ldflags) $(php-config --libs)" go build

Slide 25

Slide 25 text

Compile Xdebug gh repo clone xdebug/xdebug cd xdebug git checkout 3.3.1 phpize ./configure make #sudo make install

Slide 26

Slide 26 text

Load Xdebug ; php.ini, in the root directory of the project zend_extension = /path/to/xdebug.so xdebug_mode = debug xdebug.start_with_request = yes

Slide 27

Slide 27 text

Run GDB to Gather a Stack Trace gdb --args ./frankenphp run # Or on Apple Silicon lldb -- ./frankenphp run # “run” to start or resume execution # “bt” to show the back trace # “break example.c:17” to set a breakpoint # “p” to print variable values

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

When You Can’t Use GDB… Sometimes (e.g. in prod) you can’t install GDB. ➔ Enable verbose logs ➔ In case of segfault, enable core dumps: ulimit -S -c unlimited ➔ lsof: list open files and network sockets ➔ strace: list system calls (I/O…) ➔ top / htop: inspect CPU and memory usage ➔ …

Slide 30

Slide 30 text

Step 3: Doing Our Research

Slide 31

Slide 31 text

➔ Symfony Docker and Laravel Octane uses FrankenPHP ➔ FrankenPHP uses POSIX threads and GoRoutines (GoRoutines also use threads) ➔ Using threads requires a thread-safe (ZTS) build of PHP and of PHP extensions ➔ PHP extensions must be compatible with non-thread-safe (NTS) and thread-safe (ZTS) builds of PHP Some Context

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

The PHP Parallelism Model (NTS)

Slide 34

Slide 34 text

The PHP Parallelism Model (ZTS)

Slide 35

Slide 35 text

From The PHP Internals Book

Slide 36

Slide 36 text

Step 4: Develop Theories

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

grep -r error_reporting xdebug static void xdebug_base_overloaded_functions_restore(void) { // ... if (XG_BASE(orig_error_reporting_func)) { orig = zend_hash_str_find_ptr( EG(function_table), "error_reporting", sizeof("error_reporting") - 1 ); if (orig) { orig->internal_function.handler = XG_BASE(orig_error_reporting_func); // ...

Slide 39

Slide 39 text

No content

Slide 40

Slide 40 text

Step 5: Write and Submit a Patch

Slide 41

Slide 41 text

🎉

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Summary ➔ Step 0: COMMUNICATE ➔ Step 1: gather evidences to create a reproducer ➔ Step 2: use the right tools ➔ Step 3: use a search engine (and read books) ➔ Step 4: develop theories ➔ Step 5: contribute!

Slide 44

Slide 44 text

Thank you! Come to our booth or call us if you have weird bugs you can’t fix! les-tilleuls.coop [email protected] @coopTilleuls