--- name: schos-fedora-move-bugs description: "The two latent bugs the Fedora move exposed on 2026-08-09 — mkfs.c's DT_* ordering and the faulting stack walker in getstackpcs" metadata: node_type: memory type: project originSessionId: d4821aa9-2e49-40da-91e7-90ef9ed9997e modified: 2026-08-09T17:26:47.236Z --- Moving to the Fedora laptop ([[schos-linux-machine]]) found two bugs that had been latent for a long time. Neither is Fedora-specific; a different host and a freshly built userland simply drove code Windows never reached. ## 1. `tools/mkfs.c` would not compile at all The `DT_UNKNOWN` / `DT_DIR` / `DT_REG` fallbacks sat **above** `#include `, with the other compatibility shims. glibc spells those as enumerators (with matching macros), so `#ifndef DT_UNKNOWN` asked before the header was read, always answered "missing", and defined them — after which the header's own `enum { DT_UNKNOWN = 0, ... }` expanded to `enum { 0 = 0, ... }` and died on a syntax error pointing at the `#define`, not the cause. The fallbacks now live **below** the include, with a comment saying why. `` cannot move up instead: it has to follow the `#undef dirent` that ends the `#define dirent schfs_dirent` block, or it defines xv6's struct dirent rather than the host's. mingw-w64 never hit this because it genuinely lacks the constants. ## 2. The stack walker page-faulted, in `kernel/core/spinlock.c` Symptom: `cp` panicked the kernel with `unexpected trap 14 ... cr2=0x7`. `getstackpcs()` walked the frame chain and dereferenced `rbp[1]` without validating `rbp`. The guard rejected `0`, anything below `KERNBASE`, and `0xffffffff` — but the value that actually turns up is all-ones, `0xffffffffffffffff`, which is **above** `KERNBASE` and passed. `rbp[1]` then wrapped to address `0x7`, exactly the reported `cr2`. The `0xffffffff` test was dead code on x86-64: it is far below `KERNBASE`, so the previous check already caught it. Fixed by bounding `rbp` from above (`> (addr_t)-16`) and requiring 8-byte alignment, rather than naming another magic constant. **Why this one matters more than it looks.** `getcallerpcs()` runs on *every* lock acquisition and again from the trap handler, so a walker that can fault replaces a real diagnosis with a second, more confusing one. A backtrace helper must never be able to fault. **Why it surfaced now:** `make ports` rebuilt toybox, and the new `cp` is not the stale binary that had been staged in `sysroot/`. It drove `fileread` → `ilock` → `acquiresleep` → `acquire` → `getcallerpcs` on a path the old one did not. Rebuilding a stale userland is itself a test.