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
Commit 86202e8
Browse filesBrowse the repository at this point in the historyBrowse files
inverted run loop: confirm the mechanism on hardware
Fresh core on the CI-matching kernel. filter=-16, flags=EV_EOF|EV_ONESHOT,
udata==x0 pointing at a freed mach_kev_reg whose word 2 (0x16) matches the
MACH_DEBUG_WRAP ident from the same run. Fault is ldrb [NULL,#9] =
dux_type(du)->dst_action. Every predicted value matched; -22 ruled out.
Also: crash rate 13/30 vs 9/30 across the kernel boundary - #168 changed
nothing measurable.
Copy file name to clipboardExpand all lines: nextbsd-inverted-runloop.html
+33-2Lines changed: 33 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -284,10 +284,41 @@ <h3>The fix</h3>
284
284
285
285
<p><strong>Under 50 lines, in one file, with no kernel change and no libdispatch change</strong> — which preserves the property that this tree builds unmodified Apple libdispatch.</p>
286
286
287
-
<divclass="callout callout-warn">
288
-
<p><strong>One value would settle the last inference.</strong> The chain above is verified in source, but that <em>this particular core’s</em>faulting kevent is that event is inferred. The <code>filter</code> field of <code>_dispatch_kevent_merge</code>’s second argument decides it: <strong>−16</strong> confirms the raw-native leak above; <strong>−22</strong> would mean a synthesized event carrying a stale <code>udata</code>— a different bug needing a different fix. Cheaper than a debugger: <code>MACH_DEBUG_WRAP=1 scrltest</code> prints every synthesized delivery, and on a crashing run the fatal event will have <em>no</em> matching <code>[WRAP] deliver</code> line.</p>
287
+
<divclass="callout callout-good">
288
+
<p><strong>Confirmed on hardware, 2026-09-01.</strong> The chain above was verified in source; the remaining inference was whether <em>this</em>crash is that chain. A fresh core on the CI-matching kernel settles it — <strong>every value predicted in advance matched.</strong></p>
0x89692560: 0x000063efa4e01000 udata = 0x63efa4e01000 ← identical to x0</code></pre>
297
+
298
+
<p><strong>Filter −16</strong> is the raw-native leak; <strong>−22</strong> would have meant the sibling bug. <strong><code>EV_EOF | EV_ONESHOT</code></strong> is the exact signature <code>knlist_clear()</code> stamps on the knote in <code>ipc_pset_destroy()</code>. And the object libdispatch dereferenced:</p>
299
+
300
+
<pre><code>0x63efa4e01000: 0x0000000000000000 "du_type" → NULL (freed list pointer)
301
+
0x0000000000000007 "du_owner_wref" → 7 (an fd)
302
+
0x63efa4e01010: 0x0000000000000016 → 22
303
+
0x0000000000000017 → 23</code></pre>
304
+
305
+
<p>Two port names in a struct libdispatch believes is a dispatch unote. The cross-check that closes it: <strong><code>0x16</code> is exactly the <code>ident</code> from that run’s <code>MACH_DEBUG_WRAP</code> trace</strong> (<code>[WRAP] change kq=9 ident=0x16</code>), and <code>0x17</code> is this kevent’s own ident — tying the freed allocation to the very registration traced being created and deleted. The fault itself:</p>
<p>A NULL+9 read — <code>dux_type(du)->dst_action</code>, <code>du_type</code> at offset 0. <strong>Fix A is the correct fix; the −22 alternative is ruled out.</strong></p>
312
+
313
+
<h3>What the kernel change did <em>not</em> do</h3>
314
+
<p>The same measurement re-ran the crash rate across the kernel boundary:</p>
315
+
<table>
316
+
<tr><th>Kernel</th><th>Crashes / 30</th></tr>
317
+
<tr><td><code>20260831-232019</code> — before #167 / #168</td><tdclass="bad">13</td></tr>
318
+
<tr><td><code>20260901-032651</code> — with #167 / #168</td><tdclass="bad">9</td></tr>
319
+
</table>
320
+
<p>Statistically indistinguishable (z ≈ 1.07, p ≈ 0.28). <strong>#168 changed nothing measurable</strong>, confirming from the other direction what the bisect concluded from the dates. Note also that the crashing runs print <code>SC-RUNLOOP-OK</code> before dying — the test passes, then the manager thread faults at exit.</p>
321
+
291
322
<h2id="gnustep">10. The GNUstep question dissolves</h2>
292
323
293
324
<p>The premise behind “bring CFMachPort in side by side with GNUstep” is that the two would collide. <strong>They never meet.</strong></p>
0 commit comments