diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-03 13:10:59 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-03 13:10:59 -0300 |
| commit | ffc8c1f6f19a5dc48e98f99938b438baf9a97165 (patch) | |
| tree | 81ede7b26e6a1713597a236973014c1b64934d00 /src/CHANGELOG.md | |
| parent | 3f2d6f43199d0e230490396deb50f8dc49c7b8b0 (diff) | |
| download | pardes-ffc8c1f6f19a5dc48e98f99938b438baf9a97165.tar.gz pardes-ffc8c1f6f19a5dc48e98f99938b438baf9a97165.zip | |
crash: a panic writes itself down beside the init file, where stderr cannot lose it
Every crash this program has ever had went to stderr and nowhere else, and
stderr is the one place it cannot keep anything. In the tty shell stderr IS the
screen, so the trace lands on the grid the terminal is being reset out of; the
SDL and AppKit shells have no terminal at all; a --detach session's goes
wherever its launcher left it. src/crash.zig appends a record to
<config dir>/crashes first: one line naming the build (version, commit, UTC,
os-arch, pid) and under it the panic message and the frames behind it.
RETURN ADDRESSES and not the symbolised trace, which is measured rather than
chosen. `std.debug.writeCurrentStackTrace` called from a panic handler BEFORE
defaultPanic wedges the process at 0% CPU: symbolising reads DWARF, that read
can itself panic, and the staging which turns a nested panic into "aborting due
to recursive panic" is defaultPanic's own and private. Reproduced in a
standalone build with this program's std_options_debug_io and inside a test
binary. `captureCurrentStackTrace` only walks frames, so the addresses go in
the file and `addr2line -e` finishes the job; stderr still gets the symbolised
trace from defaultPanic, unchanged.
The AppKit shell gets a panic handler of its own here too: the macOS build
roots at macos.zig, so main.zig's had never run there — in the shell with the
least useful stderr of the four. The config directory is COPIED rather than
borrowed, because that host's lives in an arena its own errdefer frees. One
record at a time, so two panicking threads cannot interleave into one buffer.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_016Q4RATpafkwahrovHQLKRf
Diffstat (limited to 'src/CHANGELOG.md')
| -rw-r--r-- | src/CHANGELOG.md | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/src/CHANGELOG.md b/src/CHANGELOG.md index 714497b6..4fef47fc 100644 --- a/src/CHANGELOG.md +++ b/src/CHANGELOG.md @@ -2,6 +2,30 @@ ## 0.0.2 +- A panic is written down somewhere it survives. Every crash this program has + ever had went to stderr and nowhere else, and stderr is the one place it + cannot keep anything: in the TTY shell stderr IS the screen, so the trace + lands on the grid the terminal is being reset out of and the next `clear` + takes it; the SDL and AppKit shells have no terminal at all; a `--detach` + session's goes wherever its launcher left it, which is usually nowhere. So + the message and the frames behind it are now appended to `crashes` beside the + `init` file, under one line naming the build that produced them — version, + commit, UTC timestamp, os-arch and pid — which is exactly the set a bug + report needs and the set a reporter cannot be asked to reconstruct after the + fact. `src/crash.zig` runs inside the panic handler, so it takes no lock of + this program's, allocates nothing of its own, and every failure is swallowed: + a crash file that could not be written must not become the crash, and stderr + still gets its own copy either way. The file gets RETURN ADDRESSES rather + than the symbolised trace, and that is measured rather than chosen — + `writeCurrentStackTrace` called from a panic handler *before* `defaultPanic` + wedges the process at 0% CPU: symbolising reads DWARF, that read can panic, + and the staging which turns a nested panic into "aborting due to recursive + panic" is `defaultPanic`'s own and private. Walking frames is safe, so the + addresses go in the file and `addr2line -e` against the build named on the + line above them finishes the job. The AppKit shell got a panic handler of its + own in the process: the macOS build roots at `macos.zig`, so the one in + `main.zig` had never run there — in the shell with the least useful stderr of + the four. - A filtered terminal costs what an unfiltered one does. `Filter`'s second stage asked `RGB.contrast` for every cell it painted, and that call ends in `std.math.pow` six times over — a libm round trip per cell, per frame, to |
