Skip to content

Abnormal exit (crash/hard-kill) leaves a stuck commodity broker, silently blocking all future launches until reboot #71

Closed

Description

@sidick

Hypothesis

AmigaOS (pre-3.x design, still true through 3.2) has minimal automatic resource tracking and no memory protection — an application is expected to clean up its own state, and there's little OS-level safety net if it doesn't get the chance to. Correction to an earlier assumption in this thread: Intuition does not reliably auto-close a dying task's windows the way some other resources are more self-healing.

Suspected concretely: RemoveAppWindow() (src/gui/main.c:1426) — used for the QR-image drag-and-drop import — is only ever called from win_hide(), itself only reached via AmiAuth's own graceful exit paths (cleanup: at the end of main(), or the loop's own hide logic). Audited every path that sets running = 0:

  • SIGBREAKF_CTRL_C (main.c:1614)
  • CXCMD_KILL from Exchange (main.c:1648)
  • Project → Quit menu (CMD_QUIT, main.c:1810)
  • Close-gadget while not resident (main.c:1776)

All four correctly fall through to the same cleanup: path, which does call win_hide() → RemoveAppWindow(). So this is not an internal bug in AmiAuth's own shutdown logic — every exit path AmiAuth itself controls already cleans up correctly.

The gap is exits AmiAuth can't control: a hard/forced kill, or a genuine crash (a software failure / Guru Meditation was observed once this session, code 80000004, during unrelated #62 isolation testing). In either case, none of AmiAuth's cleanup code runs at all, and AddAppWindowA/RemoveAppWindow has no equivalent of the NBU_UNIQUE/NBU_NOTIFY self-healing behaviour used for the commodity broker, or the FindPort() guard used for the CLI-forwarding public port — so a stale AppWindow registration pointing at a dead window could plausibly linger in Workbench's internal state until reboot, in the same drag-and-drop subsystem already implicated in #62.

Observed symptom this session (circumstantial, not yet conclusively linked)

Repeated test-build launches occasionally failed to open a window at all until a reboot — first suspected to be a stale pre-fix AmiAuthGUI left in WBStartup:, but that was ruled out (it had been explicitly quit before one such occurrence). Not proven to be this AppWindow theory specifically, but consistent with "some previous abnormal exit left Workbench-side state that a later launch trips over."

Scope of what's actually fixable here

Nothing in AmiAuth can intercept a genuinely forced kill or a real crash on classic AmigaOS — there's no general "about to die, please clean up" hook available to ordinary tasks for that case. So the realistic work here is:

  1. Confirm (done above) that every exit path AmiAuth itself controls is already clean — regression-test this stays true as the code evolves.
  2. If the observed 80000004 crash is itself a real AmiAuth bug (not environment contamination), that's the actually-fixable root cause worth hunting down — a crash is what creates the uncleaned-exit scenario in the first place. Worth a dedicated investigation if it recurs.
  3. Document the limitation and its remedy (reboot) for users, since there's no code-level fix for the fundamental OS behaviour.

Next steps

  • Try to deliberately reproduce: hard-kill a build with accounts loaded and QR drag-and-drop having been used at least once, then check (without touching AmiAuth again) whether other apps' Workbench drag-and-drop degrades. This would confirm the AppWindow theory specifically, vs. some other leaked resource, vs. no real leak at all.
  • If reproduced, investigate whether there's any defensive mitigation available (e.g., re-registering more defensively at startup, though Workbench doesn't expose a way to query/clean existing AppWindow registrations the way FindPort() does for message ports).

Activity

  1. changed the title [-]Abnormal exit (crash/hard-kill) can leak AppWindow registration, breaking later launches[/-] [+]Abnormal exit (crash/hard-kill) leaves a stuck commodity broker, silently blocking all future launches until reboot[/+] on Jul 20, 2026
  2. sidick commented on Jul 20, 2026

    @sidick
    OwnerAuthor

    Root cause confirmed via deliberate testing (Simon, on hardware/Amiberry) — this turned out to be a different, better-evidenced mechanism than the original AppWindow hypothesis, which is now disproven. Full trail:

    Test 1: force-kill with the window open (original AppWindow theory)

    Built a KillTask dev tool (tests/tools/killtask/, force-RemTask()s a named process) to simulate an abnormal exit. In practice, Simon used a different existing tool (ARTM) to do the actual kill, since KillTask's name-matching needed a LIST mode added first (AmigaOS doesn't always name a process what you'd expect from Status's formatting).

    Result: dragging other Workbench icons stayed completely fine, both immediately after the kill and after force-closing the resulting zombie window. This rules out the AddAppWindowA/RemoveAppWindow leak as the (or at least a significant) cause of anything — the original title of this issue is no longer accurate.

    Test 2: relaunch after the kill

    Trying to launch a fresh AmiAuthGUI after the killed instance exited immediately, without even showing the passphrase requester — silent, instant exit, previously observed (unexplained) earlier in the same testing session as "window won't open."

    Traced to src/gui/main.c:1502-1510:

    broker = CxBroker(&nb, &cberr);
    if (!broker && cberr == CBERR_DUP) {
        /* Another AmiAuth is resident (now told to appear via NBU_NOTIFY);
         * leave its unlocked vault alone and exit quietly. */
        DeleteMsgPort(cxport);
        ArgArrayDone();
        close_libs();
        return 0;
    }

    The commodity broker (NBU_UNIQUE | NBU_NOTIFY, registered before any window/vault work — deliberately, so a second launch defers cleanly to a resident instance) survived the abnormal kill. commodities.library did not detect the owning task's death and free the registration, so the new launch got CBERR_DUP, correctly-per-its-own-logic assumed "another AmiAuth is already running and has been told to pop up," and quit — but the elder it deferred to is dead, so nothing happens. This is the actual explanation for the "won't open" symptom.

    Confirmed: not even Exchange can recover it

    AmiAuth is still listed in Exchange after the kill, and Exchange's own Remove does not clear it — so this isn't just a UI display quirk, the underlying commodities.library broker table is genuinely stuck. Reboot is confirmed to clear it; nothing short of that worked in testing.

    Conclusion: not fixable in AmiAuth's own code

    There's no hook available to ordinary AmigaOS tasks for "about to be killed, please clean up" on this OS, and once the broker is stuck, even the OS's own designated recovery path (Exchange Remove) can't clear it — so a code-level fix isn't possible here. This is a known-shape AmigaOS limitation (per Simon: "often with the Amiga if apps are force killed you have to reboot to clear them, or manually find them and force it") rather than an AmiAuth bug. Closing the loop with documentation instead — see the wiki Troubleshooting page update.

    tests/tools/killtask/ (the RemTask()-based force-kill dev tool, with a LIST mode for exact task-name lookup) is built but not yet committed — happy to commit it as a checked-in dev tool for future testing (mirrors movepointer's precedent) if useful, or drop it since ARTM already covers the need.

  3. sidick commented on Jul 20, 2026

    @sidick
    OwnerAuthor

    Correction: the confirmed CBERR_DUP/stuck-broker bug explains a silent, immediate exit with no passphrase prompt at all — that check (src/gui/main.c:1490) runs before any window or passphrase-prompt code. Simon has pointed out that at least one earlier "window won't open" incident this session actually showed the passphrase requester appearing first, then hanging — that's a different code path entirely (broker registration must have succeeded in that case), so it can't be the same bug. Retracting the claim that this fully explains the earlier symptoms — it explains the ARTM-kill test specifically and is a real, confirmed, separate bug worth keeping documented, but there may be at least one other distinct issue still unexplained (something hanging after the passphrase requester shows). Narrowing that down separately.

  4. sidick commented on Jul 20, 2026

    @sidick
    OwnerAuthor

    Parking this until the "passphrase requester closes, no window appears" symptom can be reliably reproduced (not seen recently). Current working theory (unconfirmed): the very first LISTBROWSER_Labels relist after every unlock still has to happen even with #70's throttle (codes need to populate the list somehow) — if a single relist call is expensive enough on its own, it could still occasionally block the newly-opened window's first paint, distinct from the ongoing per-second stall #70 already fixed. Needs reproduction to confirm either way.

    If the 80000004 software failure shows up again during a future session, SegTracker (resident tool, OS 2.04+) symbolicates crash addresses back to source/file/line — worth having loaded, since right now there's no information about where that crash actually happened or whether it's an AmiAuth bug at all. (It doesn't help with resource-leak tracking, so not relevant to the broker/CBERR_DUP finding above — different tool for a different symptom.)

  5. sidick commented on Jul 21, 2026

    @sidick
    OwnerAuthor

    The parked "passphrase requester closes, then no window appears" symptom is explained — and it wasn't the LISTBROWSER-relist theory.

    Root cause: the startup SNTP sync ran between the passphrase prompt and win_show, and clock_sntp_sync starts with a blocking gethostbyname() whose timeout belongs to the TCP/IP stack's resolver — against a dead or black-holed DNS server that's routinely tens of seconds, plus up to 5 s of UDP wait after it. With a stack running but the network down (a normal Amiberry test-session state), the requester closed and the window didn't appear until the resolver gave up. It also explains why the symptom vanished "recently": with no stack configured, the bsdsocket open fails instantly and the sync skips.

    Reproduced deliberately under Copperline: a 30 s stall injected at the sync call site, screenshot at t=35 s — old ordering shows a bare desktop (gui-smoke's window assertion fails, unique_colours=1), new ordering (window first) shows the window painted with the stall running behind it.

    Fix: PR #95 moves the sync to after win_show — worst case becomes a visible, briefly-unresponsive window (amber LED, placeholder codes) instead of an invisible hang, with the status line/LED refreshing the moment the sync returns. Docs updated accordingly.

    Remaining loose end from this issue's trail: tests/tools/killtask/ was never committed and isn't on disk locally — it would need rebuilding from scratch if wanted (ARTM covered the actual testing). Happy to recreate it as a checked-in dev tool, or this issue can close with #95.

  6. sidick commented on Jul 21, 2026

    @sidick
    OwnerAuthor

    Closing with PR #95 merged. Final state of everything this issue tracked:

    • Stuck broker after force-kill/crash: confirmed unfixable at the code level (commodities.library doesn't detect owner death; even Exchange Remove can't clear it). Documented in Troubleshooting with the reboot remedy.
    • "Requester closes, no window" symptom: root-caused to the blocking DNS/SNTP sync sitting between unlock and window-open, deliberately reproduced on-target, fixed in GUI: open the window before the startup SNTP sync #95 (window opens first; docs updated).
    • killtask dev tool: dropped — ARTM covers the force-kill testing need; not worth recreating and maintaining.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions