<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Debugging on Luther Monson</title>
    <link>https://luth.io/tags/debugging/</link>
    <description>Recent content in Debugging on Luther Monson</description>
    <generator>Hugo</generator>
    <language>en</language>
    <lastBuildDate>Mon, 12 Oct 2026 21:10:00 -0700</lastBuildDate>
    <atom:link href="https://luth.io/tags/debugging/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Step Debugging a Worker That Never Ends</title>
      <link>https://luth.io/blog/2026/10/xdebug-worker-mode/</link>
      <pubDate>Mon, 12 Oct 2026 21:10:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/10/xdebug-worker-mode/</guid>
      <description>&lt;p&gt;Persistent workers are the big performance win in modern PHP. You boot Laravel or Symfony once, keep the container&#xA;in memory, and serve thousands of requests out of the same process. &lt;a href=&#34;https://github.com/ephpm/ephpm&#34;&gt;ePHPm&lt;/a&gt; has had&#xA;a worker mode for a while. Like most worker runtimes it had a quiet hole in it. You couldn&amp;rsquo;t step debug a request with&#xA;Xdebug. I wanted that fixed without patching Xdebug and without giving up the warm pool. The answer ended up being to&#xA;stop fighting the constraint and route around it. The debug lane is merged on main and coming in the upcoming v0.12.0&#xA;release.&lt;/p&gt;</description>
    </item>
    <item>
      <title>An Upstream PHP JIT Use-After-Free, and Why Our Default Flipped Twice</title>
      <link>https://luth.io/blog/2026/10/php-jit-use-after-free/</link>
      <pubDate>Thu, 01 Oct 2026 20:10:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/10/php-jit-use-after-free/</guid>
      <description>&lt;p&gt;In August, &lt;a href=&#34;https://github.com/ephpm/ephpm&#34;&gt;ePHPm&lt;/a&gt; turned PHP&amp;rsquo;s tracing JIT on by default in single-site serve mode.&#xA;Three days later it went back off on every platform, and it&amp;rsquo;s still off. The reason turned out to be a use-after-free&#xA;in PHP&amp;rsquo;s tracing JIT that has nothing to do with ePHPm. Stock &lt;code&gt;php -S&lt;/code&gt; with a stock Laravel skeleton dies on it in a&#xA;couple of requests. The fix is now released upstream. So this seemed like the right time to write up how we got there,&#xA;and what still has to happen before the default can flip again.&lt;/p&gt;</description>
    </item>
    <item>
      <title>os/exec&#39;s StdoutPipe Footgun: How cmd.Wait() Ate My Last Frame (Twice)</title>
      <link>https://luth.io/blog/2026/09/os-exec-stdoutpipe-wait-footgun/</link>
      <pubDate>Thu, 17 Sep 2026 20:12:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/09/os-exec-stdoutpipe-wait-footgun/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://luth.io/blog/2026/08/shipmates-persona-based-ai-coding-crews/&#34;&gt;shipmates&lt;/a&gt; spends most of its life spawning &lt;code&gt;claude&lt;/code&gt; (and&#xA;&lt;code&gt;codex&lt;/code&gt;) processes and reading newline-delimited JSON off their stdout. The last frame of a turn is the important one.&#xA;It&amp;rsquo;s a &lt;code&gt;result&lt;/code&gt; frame with the cost, the model and the final text. Stderr matters too, because that&amp;rsquo;s where Claude Code&#xA;tells you &lt;code&gt;Invalid API key · Please run /login&lt;/code&gt;. For a while I was throwing both away under load. The cause is&#xA;documented right there in the &lt;code&gt;os/exec&lt;/code&gt; godoc. I fixed it in one package and then found the exact same bug again a&#xA;month later in another.&lt;/p&gt;</description>
    </item>
    <item>
      <title>OPcache on Windows: Two Silent Failures</title>
      <link>https://luth.io/blog/2026/08/opcache-on-windows-two-silent-failures/</link>
      <pubDate>Sat, 29 Aug 2026 16:45:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/08/opcache-on-windows-two-silent-failures/</guid>
      <description>&lt;p&gt;Windows is the platform where &lt;a href=&#34;https://github.com/ephpm/ephpm&#34;&gt;ePHPm&lt;/a&gt; gets the least traffic and the most surprises.&#xA;Last week closed out two OPcache bugs that only exist there. Both were quiet in their own way. One killed the server&#xA;at startup with nothing in our own logs. The other didn&amp;rsquo;t kill anything. It just ran PHP 8.3 with no opcode cache at&#xA;all. For three weeks after a fixed SDK was published, every check stayed green.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Requests That End Wrong: A 200 That Was Really a Crash</title>
      <link>https://luth.io/blog/2026/08/requests-that-end-wrong/</link>
      <pubDate>Thu, 13 Aug 2026 21:14:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/08/requests-that-end-wrong/</guid>
      <description>&lt;p&gt;The scariest response a server can send isn&amp;rsquo;t a 500. It&amp;rsquo;s a 200 that should have been a 500. A crash is loud. The pod&#xA;restarts, an alert fires, somebody looks. A truncated page with a success status code is quiet. Your CDN caches it and&#xA;the health check calls the box healthy. A client parses half a document as if it were the whole thing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/ephpm/ephpm&#34;&gt;ePHPm&lt;/a&gt; embeds PHP inside a Rust server. So we own the part of PHP that php-fpm&#xA;normally owns: starting a request, running the script and ending it. Over the last couple of months I&amp;rsquo;ve fixed three&#xA;bugs that all live in that start-and-end code. None of them were in the SAPI I/O callbacks like &lt;code&gt;ub_write&lt;/code&gt; and&#xA;&lt;code&gt;read_post&lt;/code&gt;, where you&amp;rsquo;d expect to find embed bugs. They were in the Zend request lifecycle and in TSRM teardown.&#xA;That&amp;rsquo;s code you never touch when you run PHP behind php-fpm.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rescuing a Windows Dynamic Disk Over USB with WSL2 and USB/IP</title>
      <link>https://luth.io/blog/2026/08/windows-dynamic-disk-usb-wsl2-usbip/</link>
      <pubDate>Sat, 01 Aug 2026 13:15:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/08/windows-dynamic-disk-usb-wsl2-usbip/</guid>
      <description>&lt;p&gt;I pulled a 1 TB NVMe out of an old Windows box, dropped it in a USB enclosure and plugged it in. Windows showed nothing.&#xA;No drive letter, no &amp;ldquo;initialize this disk&amp;rdquo; prompt, nothing in Explorer. Disk Management listed it as &lt;code&gt;Invalid&lt;/code&gt;. The&#xA;enclosure&amp;rsquo;s booklet said to &amp;ldquo;bring the disk online&amp;rdquo;, which silently did nothing. The data was completely intact. Windows&#xA;was refusing on &lt;strong&gt;policy&lt;/strong&gt; grounds, not because anything was broken. Getting it back meant going around the Windows&#xA;storage stack entirely. I handed the raw USB device to a Linux kernel that doesn&amp;rsquo;t share Windows&amp;rsquo; opinions.&lt;/p&gt;</description>
    </item>
    <item>
      <title>PHP Signal Safety - The Init Ordering Bug Nobody Warns You About</title>
      <link>https://luth.io/blog/2026/04/php-signal-safety-init-ordering/</link>
      <pubDate>Sun, 12 Apr 2026 20:15:00 -0700</pubDate>
      <guid>https://luth.io/blog/2026/04/php-signal-safety-init-ordering/</guid>
      <description>&lt;p&gt;Last week I wrote about &lt;a href=&#34;https://luth.io/blog/2026/04/why-rust-for-php-embedding/&#34;&gt;why ePHPm embeds PHP from Rust&lt;/a&gt; and promised the&#xA;signal bug its own post. Here it is. It&amp;rsquo;s the kind of bug where the fix is about ten lines and the explanation is the&#xA;whole post. Nothing in PHP&amp;rsquo;s embed documentation (there&amp;rsquo;s barely any) tells you that initializing PHP has&#xA;process-wide side effects. Those side effects assume PHP is the only thing in the process.&lt;/p&gt;&#xA;&lt;h3 id=&#34;the-setup&#34;&gt;The setup&lt;/h3&gt;&#xA;&lt;p&gt;The first working version of &lt;code&gt;ephpm serve&lt;/code&gt; looked like every async Rust program. It was &lt;code&gt;#[tokio::main]&lt;/code&gt;-style. Build&#xA;the runtime, then inside it load config, initialize PHP and start the HTTP server. PHP requests run on&#xA;&lt;code&gt;spawn_blocking&lt;/code&gt; threads. Simplified:&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
