Become a Patron!

My Amazon wishlist can be found here.

Life Line

Adverse ABIs

After last week's release candidate I started receiving some bug reports that Xdebug nearly instantaneously crashed PHP. Upon further investigation, it turned out to only be a problem on macOS, which is good as that's not affecting everybody, but bad as I don't have a macOS machine to try to reproduce things on.

I did some screen sharing with Frédéric Marand in order to dive down what the problem was, but we couldn't really get to the problem. It looked like there was nothing really wrong, until Xdebug called the php_addslashes C function (which is the internal implementation of addslashes). This matched the exact same location as David Vuorio showed in his stack trace in the bug tracker.

Still tearing my hairs out, I contacted Nikita Popov to see if he knew whether there was anything special about php_addslashes. His reply:

I have some suspicions...

And his suspicion turned out to be right.

PHP 7.3 has received many optimisations. One of them is the use of specific CPU instructions to speed up certain tasks. In this case, the PCMPESTRM instruction is used to find whether a string has characters that need to be escaped.

Upon build time, PHP's ./configure script checks whether the CPU it is built on supports these newer CPU instructions. If so, it then uses some header magic to use a specialised version of php_addslashes. This works fine if both PHP and the extension that uses php_addslashes are compiled on the same machine. However, if PHP is compiled on a machine without support, and the extension (Xdebug) is compiled on a machine with support, then the ABI (calling convention) of the php_addslashes C function is different. A crash will then occur when the extension tries to call the PHP php_addslashes function "in the wrong way". And that is exactly what happened here: the PHP binary that came from Homebrew uses a different ABI then the Xdebug binary that users compiled themselves. Modifying the installed headers made the problem go away.

Nikita soon fixed this in the PHP 7.3 branch with a hack to make sure that the ABI among PHP 7.3 versions stays the same, and a proper fix for PHP 7.4 and later to prevent this situation from occurring in the feature. Xdebug works around it for PHP 7.3.0 and PHP 7.3.1. Instead of relying on PHP's implementation of php_addslashes (xdebug_add_slashes), it uses its own. It also uses its own implementations of php_base64_encode and php_base64_decode which exhibit a similar issue. As Xdebug's implementations are slightly modified to work better for Xdebug, there is a minimal performance improvement too.

Time for Release Candidate 2!


This article has a short URL available:


No comments yet

Memory Madness

I'm currently preparing Xdebug for its 2.7.0rc1 release, the first (and hopefully last) release candidate. There is one issue left to do, and that is the one I have been working on in the last days.

The crash popped up when running the Zeta Components test suite for the Document component. And it manifests itself through a Segmentation Fault:

derick@gargleblaster:~/dev/zetacomponents-document$ php  ~/phpunit-5.7.22.phar
PHPUnit 5.7.22 by Sebastian Bergmann and contributors.

.............................................................   61 / 1198 (  5%)
...............................S.............................  122 / 1198 ( 10%)
..............................................E......Segmentation fault

When running it from within gdb, we see:

.............................................................   61 / 1198 (  5%)
...............................S.............................  122 / 1198 ( 10%)
..............................................E..............  183 / 1198 ( 15%)
...............S.....S.....SS................................  244 / 1198 ( 20%)
...................................E.......F.................  305 / 1198 ( 25%)
..........E..................F..E............................  366 / 1198 ( 30%)
.............................................................  427 / 1198 ( 35%)
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff17a96fb in zval_get_type (pz=0x42) at /usr/local/php/7.3.0/include/php/Zend/zend_types.h:411
411             return pz->u1.v.type;
(gdb) bt
#0  0x00007ffff17a96fb in zval_get_type (pz=0x42) at /usr/local/php/7.3.0/include/php/Zend/zend_types.h:411
#1  0x00007ffff17ad2dc in xdebug_var_export (struc=0x7fffffff7c68, str=0x555558f36490, level=1, debug_zval=0, options=0x5555590c3cc0) at /home/derick/dev/php/xdebug-xdebug/xdebug_var.c:974
#2  0x00007ffff17ad812 in xdebug_get_zval_value (val=0x555559180120, debug_zval=0, options=0x5555590c3cc0) at /home/derick/dev/php/xdebug-xdebug/xdebug_var.c:1059
#3  0x00007ffff17a1f11 in add_single_value (str=0x7fffffff7dd0, zv=0x555559180120, html=0, collecton_level=4) at /home/derick/dev/php/xdebug-xdebug/xdebug_stack.c:371
#4  0x00007ffff17a23dd in xdebug_append_printable_stack (str=0x7fffffff7dd0, html=0) at /home/derick/dev/php/xdebug-xdebug/xdebug_stack.c:451
#5  0x00007ffff1782089 in xdebug_throw_exception_hook (exception=0x7fffe96ae200) at /home/derick/dev/php/xdebug-xdebug/xdebug.c:1586

But these errors can sometimes be misleading. As you can see, the error now happens a bit later during the test run.

In these cases, I usually use Valgrind instead, as it gives a warning as soon as a memory issue occurs, such as a use-after-free situation, or when reading uninitialised memory.

Running the tests with Valgrind however, gave very strange results:

derick@gargleblaster:~/dev/zetacomponents-document$ valgrind php ~/phpunit-5.7.22.phar --filter ezcDocumentConverterDocbookToRstTests::testLoadXmlDocumentFromFile
==38610== Memcheck, a memory error detector
==38610== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==38610== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==38610== Command: php /home/derick/phpunit-5.7.22.phar --filter ezcDocumentConverterDocbookToRstTests::testLoadXmlDocumentFromFile
==38610== Conditional jump or move depends on uninitialised value(s)
==38610==    at 0x4035D2A: ???
==38610==    by 0x13E352D7: ???
==38610==    by 0x13E352D7: ???
==38610==    by 0x13E352F6: ???
==38610==    by 0xB102CCF: ???
==38610==    by 0x13E352D7: ???
==38610== Conditional jump or move depends on uninitialised value(s)
==38610==    at 0x4035D2A: ???
==38610==    by 0x13EE3BA7: ???
==38610==    by 0x13EE3BA7: ???
==38610==    by 0x13EE3BC6: ???
==38610==    by 0xB102CCF: ???
==38610==    by 0x13EE3BA7: ???

Normally, these ??? items contain the name of C functions, but in this case, they are all unknown. That often means that Valgrind does not have the right debugging symbols available. After checking whether I had these installed, I found that I did have the debugging symbols available. Another point is that usually, at least there is some recognisable name present in stack traces for uninitialised value(s).

I first thought I had a bug in Valgrind, or perhaps the packaging was not done right for my Linux distribution. I know somebody who works on Valgrind, so I asked on IRC whether he knew what was up. Beyond the debugging symbols, he couldn't provide additional suggestions either. But Nicolás Álvarez, who was also hanging out in the channel, asked whether PHP has a JIT engine. I answered that it doesn't (yet), and then the light bulb went off: Although PHP itself does not have a JIT, the PCRE regular expression engine that PHP uses does.

After disabling PCRE's JIT with -dpcre.jit=0, the Valgrind output is now what I expect—with just the memory error that I thought was happening:

derick@gargleblaster:~/dev/zetacomponents-document$ valgrind php -dpcre.jit=0 ~/phpunit-5.7.22.phar --filter ezcDocumentConverterDocbookToRstTests::testLoadXmlDocumentFromFile
==38648== Memcheck, a memory error detector
==38648== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==38648== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==38648== Command: php -dpcre.jit=0 /home/derick/phpunit-5.7.22.phar --filter ezcDocumentConverterDocbookToRstTests::testLoadXmlDocumentFromFile
PHPUnit 5.7.22 by Sebastian Bergmann and contributors.

.....==38648== Invalid read of size 4
==38648==    at 0xB63E37E: xdebug_zend_hash_is_recursive (xdebug_compat.c:260)
==38648==    by 0xB65F1CF: xdebug_var_export (xdebug_var.c:965)
==38648==    by 0xB65F811: xdebug_get_zval_value (xdebug_var.c:1059)
==38648==    by 0xB653F10: add_single_value (xdebug_stack.c:371)
==38648==    by 0xB6543DC: xdebug_append_printable_stack (xdebug_stack.c:451)
==38648==    by 0xB634088: xdebug_throw_exception_hook (xdebug.c:1586)
==38648==    by 0x9BF803: zend_throw_exception_internal (zend_exceptions.c:166)
==38648==    by 0x9C3413: zend_throw_exception_object (zend_exceptions.c:1046)
==38648==  Address 0x1426f774 is 4 bytes inside a block of size 56 free'd
==38648==    at 0x4C2CDDB: free (vg_replace_malloc.c:530)
==38648==    by 0x95E07A: _efree (zend_alloc.c:2508)
==38648==    by 0x9A95C3: zend_array_destroy (zend_hash.c:1513)
==38648==    by 0x99043A: zend_array_destroy_wrapper (zend_variables.c:90)
==38648==    by 0x9902C5: rc_dtor_func (zend_variables.c:65)
==38648==    by 0x9ED835: zend_assign_to_variable (zend_execute.h:108)
==38648==    by 0xA54307: ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUSED_HANDLER (zend_vm_execute.h:45824)
==38648==    by 0x9FA722: ZEND_USER_OPCODE_SPEC_HANDLER (zend_vm_execute.h:1829)
==38648==  Block was alloc'd at
==38648==    at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==38648==    by 0x95ECFF: __zend_malloc (zend_alloc.c:2904)
==38648==    by 0x95DFD3: _emalloc (zend_alloc.c:2494)
==38648==    by 0x9AAAAA: zend_array_dup (zend_hash.c:1923)
==38648==    by 0xA5664A: ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_DATA_CV_HANDLER (zend_vm_execute.h:47041)
==38648==    by 0x9FA722: ZEND_USER_OPCODE_SPEC_HANDLER (zend_vm_execute.h:1829)
==38648==    by 0xA5F7D9: execute_ex (zend_vm_execute.h:55557)
==38648==    by 0xB634E90: xdebug_execute_ex (xdebug.c:1876)

And with the insight this gave me, I can now attempt to find and fix the bug, and finally release Xdebug 2.7.0rc1.


This article has a short URL available:


Building PHP with --with-pcre-valgrind should help with those PCRE related errors you're seeing.

The Xdebug Experience

Xdebug development is currently in its 17th year. I started working on it when PHP 4.2.0 had just been released. The first CVS commit added the (in)famous "maximum nesting level" functionality, to prevent PHP from crashing when your script would infinitely recurse. I had forgotten this, but apparently Xdebug has some origins in VL-SRM, a naive attempt to create an application server running PHP bananas (think of: Java beans). The VL prefix still lives on as part of my PHP internals debugging extension VLD.

Where Are We Now?

As with any legacy project, Xdebug has technical debt. Some of it I managed to address during the years by dropping support for older PHP versions. There is a fair amount of sub-optimal code, algorithmic, and design issues, which impact ease of configuration, usability, and performance.

Configuration Confusion

On the configuration side, take for example the 65 configuration settings. There are a few pointless ones (xdebug.extended_info, xdebug.remote_handler), a few that duplicate functionality (xdebug.trace_output_dir and xdebug.profiler_output_dir), and a few that should never be used together (xdebug.remote_enable and xdebug.profiler_enable).

Unproductive Usability

If we look at usability, there are situations where breakpoints don't break. Some of these I can likely address, whereas others I can not due to the way how PHP works internally (See also: The Mystery of the Missing Breakpoints). Having OPcache in the mix does not help either as it can create another set of problems where visible code has been optimised out.

To solve a third group of issues with breakpoints, the DBGp "breakpoint resolved" notification needs to be implemented in both Xdebug and IDEs.

Another issue is that both Xdebug and PHP-FPM use port 9000 as their default, although Xdebug's use of port 9000 precedes PHP-FPM's by about five years (2004 vs 2009).

And lastly, (potential) users often cite that it is "hard" to set Xdebug up. Although after talking to some of these users, it often becomes clear that the problem is not so much on the Xdebug side of things, but rather other tools: their IDE, Docker, SELinux, firewalls, etc. Improving this is a matter of education (and better error messages).

Poor Performance

On the performance side, there are some places with major issues, and some others with minor issues. Code coverage isn't particularly fast, and that needs an in-depth investigation. I have several ideas on where improvements in code coverage performance can be made—nonetheless, I would continue to put correctness over speed.

Even with Xdebug just loaded and enabled, there is too much of a performance impact. This is because Xdebug usually has every feature ready to go, even though you don't necessarily want to use all of these different features. For example, it is ludicrous to use single step debugging with the profiler turned on.

Although it's often possible to reduce the impact of feature sets by setting configuration options correctly, a better way to put Xdebug in a specific mode would be welcome.

What Needs to Be Done?

In order to address many of these problems, Xdebug must undergo a massive refactoring. As part of that effort, the refactoring must primarily focus on solving the above mentioned three categories, although improvements in code layout are also desirable.

As part of the refactoring process, the following primary tasks need to be completed, in preferably the listed order:

  • Finalize PHP 7.3 support (there is a nasty bug where Xdebug and a specific OPcache optimisation setting conflict).

  • Code needs to be reorganised, as the current location of source files and functions is detrimental to improvements.

  • The number of configuration options needs to be reduced.

  • Modes needs to be introduced, so that it is easier to turn off and on (internal) code to support different features. This will very likely improve general performance already.

  • Specific code paths and features need to be optimised. This includes primarily the basic features (stack traces, var_dump() improvements, etc.), as well as Code Coverage.

What is Needed to Get This Done?

I would love to be able to continue to work on Xdebug; to keep it in sync with changes in PHP itself, to implement the ideas from this article to improve the Xdebug Experience, and to produce educational material such as improved documentation, tutorials, and videos. (Dare I say a book?)

Therefore I am currently looking for ways that I can be funded for doing all the required work. It will take a lot of time to get Xdebug 3 out in a tip-top shape. Possibly, if not more, than 6 months. Although I have plenty of time now that I've left MongoDB, the bills and mortgage do need to get paid too. I can think of a few options:

  • Get more users to sign up to my Patreon account. There is a group of loyal users and companies that contribute towards the upkeep of the server. But in order to make this sustainable, the patron count need to increase about 30 fold. I struggle with setting up rewards to nudge people to support me.

  • A fundraiser (through a crowd funding site) for specific tasks and/or features from the plan.

  • Some functionality that would only be available under a commercial license. One of the ideas here is to add a recording feature that records the full execution of a script, which then later can be replayed back through an interactive single step debugging session in an IDE.

  • Work with IDE manufacturers to implement some of their requested features (such as the before mentioned "resolved breakpoint" notification), and to come up with new features to make the debugging experience better.

I am interested to hear whether you have a specific preference, or perhaps some additional suggestions for me to consider. I would absolutely want to give Xdebug all the love it still deserves after 17 years. Let me know what you think! Either in a comment, or by email.

cheers, Derick


This article has a short URL available:


I don't do Patreon, but I do want to contribute. Are there other ways? Paypal?

I love Xdebug as it is. Because it's so useful, not because it's no easy. Everybody should use it. Making it easier and faster would be a great start!

Hi Derick. I'd be interested to hear why each new version of PHP requires specific support in Xdebug, rather than "just working". Maybe you could do a post on that? :)

Im in! Will support this undertaking.

Xdebug is key to almost everything I do in PHP, and I use it everyday. Without it, PHP would not have the same value to me, and I'm not sure that I would even continue using PHP. IMO, it is critical that Xdebug's core functionality remains FOSS, though I understand the need for a sustainable model.

I have seen some other developers struggle to get started with Xdebug, even though they really want to use it. In order to get a larger userbase, it may be worthwhile to consider ease-of-use so that a beginner has some intuition as to why Xdebug is not working for them if it is not configured correctly.

I signed up on Patreon. If anyone sees this and are at all interested in the future of PHP, I encourage you to do the same.

Throw up both Bitcoin and Ethereum addresses. I'll donate.

I propose that you work on making it mindnumbingly easy to use xdebug. You say that you talked to users who mention that it’s too difficult to set up, and that you always concluded that it was caused by external tools or IDEs, but I think how you should treat these comments is to see it as a signal from the user that it’s actually not so easy to start using the software.

For example, if you go and have a look at the Reddit thread about this post, you will see that some of the most highly voted comments are about how people try to use xdebug but gave up. Basically, I think you should treat that as being unacceptable. Potential users not being able to use your software is bad for you and bad for them.

Perhaps it’s an idea to store all related settings into a JSON file, that people could commit to their repositories? At the first start up this JSON file can then be read and used to set up xdebug? Or perhaps it’s better to investigate some sort of server-client procedure with a configuration exchange in the beginning of a new connection? I don’t know. I am not familiar enough with the internals to make a good suggestion here.

I just think that it should be much easier to start using your software, it should basically be so simple that an idiot can do it with his eyes closed, every time, without fail, and without doing any configuration. Just my 2 cents. Thanks for all your great work over the years!

I subscribed to Patreon for an 5 USD per month support. Thank you for your support.

Hi Derick,

I was wondering if you could set up a corporate sponsors page on your site where we can have a small banner and a link if we pay you a monthly fee?

What do you think?




Thanks for all the comments, I'll reply to them all in this comment of my own:

@Rudie: I don't have PayPal, as they're keen on holding on to money without telling me why, and making me wait for it. I am imploring whether I can sell licences, but that will likely have to be done more formally (with an invoice, and a bank transfer, or something like that).

@Jonathan: Each PHP version changes the internals of the language. Xdebug needs to dive deep into these internals to be able to do what it does. I can explain that better with a real example, and will endeavour to write a post when this happens the next time—I already know there are a few changes needed for PHP 7.4.

@Theodore: I don't know how Bitcoin and/or Ethereum work really. I might consider looking at that in the future, but right now, I don't have any plans to create accounts and wallets for them.

@Zach, @Ed, and @Robbert: Thanks for your comments.

@Nolwenn: Thanks for the suggestion. I have no plans to create an area where I provide links to companies that want to sponsor. I have already received many of these requests in the past, and most of them were dodgy outfits. Because I don't really want to say yes to some, and no to others, I have long ago decided that I don't want to go this route.



Would be great if we could buy some cool Xdebug elephants!

Have you considered

@Willem: Yes, that would be nice, but it's also a lot of work, and I'm not sure for how much gain...

@Stephen: Yes, I have heard of, and if I would do a bit, I would likely go that route.

Re: Modes: Have you considered splitting xdebug into different modules?

Profiler and debugger are not intended to be run together, even though they share a lot of common code. Which would reduce configuration issue by a lot.

I already used to use a wrapper to run scripts with debugger loaded, so that my regular maintenance tasks aren't influenced by xdebug. It just works, like if I'm running a different SAPI.