summaryrefslogtreecommitdiff
path: root/docs/config.md
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-03 13:29:50 -0300
committerGabriel Schneider <[email protected]>2026-09-03 13:29:50 -0300
commite6c9f1726cca910c464fc807aefebc404c8e7a12 (patch)
tree0bbcb79ae26a006afa40a4a8b26215a81610fb49 /docs/config.md
parent7c6165f184e45af30ac697f8e8a584529ac4a287 (diff)
downloadpardes-e6c9f1726cca910c464fc807aefebc404c8e7a12.tar.gz
pardes-e6c9f1726cca910c464fc807aefebc404c8e7a12.zip
crash: a panic record must not be able to hang the process it is recording
Adversarial re-review, confirmed against std's source and then measured. `captureCurrentStackTrace` is not the safe half of `writeCurrentStackTrace`. `StackIterator.init` picks the `.di` strategy whenever `SelfInfo` can unwind, `stratOk` accepts `.di` regardless of `allow_unsafe_unwind`, and `.di` takes `SelfInfo`'s rwlock EXCLUSIVELY on its first call — the only kind of call a panic record makes — across `dl_iterate_phdr`, a DWARF CFI machine and an allocation. A panic in there (a smashed stack is a leading reason to be in a panic handler at all) leaves the lock held, because the unlock is a `defer` in a frame that never returns, and `defaultPanic` then waits on it for the life of the process. A crash becomes a hang, which is worse than what this file was added to improve on. The frames stay on stderr, where defaultPanic prints them under the staging that makes them safe; the record keeps what can be gathered without asking the process any questions. ONE record per process, never released. With the guard released on the way out, one panic wrote two records: the real message, then "reached unreachable code" under it. That second panic is this handler's own `vaxis.recover()` running a second time — it closes the vaxis tty and never clears the global saying there is one, so the double close is `recoverableOsBugDetected` and an `unreachable` in a Debug build. Guarded now in both the panic and the segfault handler; that half is a fix older than the crash file. `clock_gettime`'s return is checked, unlike dump.zig's, because a failure here leaves `ts` undefined and an undefined large-positive `sec` walks `calculateYearDay`'s u16 year past 65535 and overflow-panics inside the panic handler. Debug fills it with 0xaa and lands in 1970, which is why it reads as harmless. Verified end to end with a temporary probe: one panic, one record. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_016Q4RATpafkwahrovHQLKRf
Diffstat (limited to 'docs/config.md')
-rw-r--r--docs/config.md24
1 files changed, 12 insertions, 12 deletions
diff --git a/docs/config.md b/docs/config.md
index b95f207e..448ac763 100644
--- a/docs/config.md
+++ b/docs/config.md
@@ -102,24 +102,24 @@ the one place this program cannot keep a trace: in the TTY shell stderr IS the
screen, so the trace lands on a grid the terminal is being reset out of; the SDL
and AppKit shells have no terminal at all; and a `--detach` session's stderr
goes wherever its launcher left it. The file is appended, never rewritten, and
-each record is one line of build metadata, the panic message, and the return
-addresses behind it:
+each record is two lines — build metadata, then the panic message:
```text
pardes 0.0.2 (a1b2c3d) 2026-09-03T11:20:44Z linux-x86_64 pid 48812
panic: index out of bounds: index 4, len 4
- 0x11ccb5a
- 0x11cc84c
- 0x11cc67a
```
-`addr2line -e <the pardes binary>` turns those into source lines, against the
-build the metadata line names. They are addresses rather than the symbolised
-trace stderr gets for a measured reason: symbolising from inside a panic
-handler, before `std.debug.defaultPanic` has run, HANGS the process — reading
-DWARF can itself panic, and the staging that turns a nested panic into
-"aborting due to recursive panic" is `defaultPanic`'s own and private. Walking
-frames is safe; symbolising them is not.
+NO STACK TRACE, and that is a measured decision rather than an omission. The
+frames stay on stderr, where `std.debug.defaultPanic` prints them. Collecting
+them here instead HANGS the process: `writeCurrentStackTrace` called from a
+panic handler before `defaultPanic` has run wedges at 0% CPU, and
+`captureCurrentStackTrace` — which looks like the safe half — takes `SelfInfo`'s
+rwlock exclusively on its first call, so a panic inside the walk leaves that
+lock held and `defaultPanic` then waits on it forever. What makes `defaultPanic`
+survive the same hazard is its own private `panic_stage`, which nothing outside
+`std.debug` can reach. A crash that becomes a hang is worse than the crash, so
+this file keeps only what it can gather without asking the process any
+questions: which build, when, where, and what it said.
Everything about it is best effort and silent: no config directory (a launch
with no `HOME`) means no file, and a directory that cannot be created or opened