Renaming a status is not safe against a concurrent lookup #7

Open
opened 2026-08-02 18:59:08 -04:00 by tachikoma · 0 comments
Collaborator

Source: TODO.md §5 (at 5695061)

akerr_name_for_status(status, NULL) returns a pointer into the registry rather
than a copy
, which is what makes it usable from inside FAIL -- it needs no
buffer and no error context of its own.

Registering a second name for a status that already has one
(tests/err_name_ownership.c covers that it is allowed) overwrites that buffer
in place, so a thread reading the name at that moment can see a torn string.

Every other registry operation is serialized; this one cannot be, because the
reader is outside the lock by the time it reads the characters.

Documented in docs/thread-safety.md and UPGRADING.md as "register names during
initialization". Closing it properly means making a registered name immutable,
and there are two shapes:

  1. Refuse a rename outright. A behaviour change, and
    tests/err_name_ownership.c asserts the current contract.
  2. Copy names into a bump-allocated arena and publish the pointer with a release
    store
    , so a rename allocates new storage instead of rewriting live storage.

The arena is the better answer; it costs a second capacity limit and its
exhaustion path.

Files: src/error.c, tests/err_name_ownership.c, docs/thread-safety.md


Filed by Tachikoma (Claude Code, Opus 5, 1M context)

**Source:** TODO.md §5 (at 5695061) `akerr_name_for_status(status, NULL)` **returns a pointer into the registry rather than a copy**, which is what makes it usable from inside `FAIL` -- it needs no buffer and no error context of its own. Registering a *second* name for a status that already has one (`tests/err_name_ownership.c` covers that it is allowed) **overwrites that buffer in place, so a thread reading the name at that moment can see a torn string.** **Every other registry operation is serialized; this one cannot be**, because the reader is outside the lock by the time it reads the characters. Documented in `docs/thread-safety.md` and `UPGRADING.md` as "register names during initialization". Closing it properly means making a registered name immutable, and there are two shapes: 1. **Refuse a rename outright.** A behaviour change, and `tests/err_name_ownership.c` asserts the current contract. 2. **Copy names into a bump-allocated arena and publish the pointer with a release store**, so a rename allocates new storage instead of rewriting live storage. **The arena is the better answer**; it costs a second capacity limit and its exhaustion path. **Files:** `src/error.c`, `tests/err_name_ownership.c`, `docs/thread-safety.md` --- Filed by Tachikoma (Claude Code, Opus 5, 1M context)
tachikoma added this to the 3.0.0 milestone 2026-08-02 18:59:08 -04:00
tachikoma added the defectdesign-decisionblast-radius:mediumstatus::grooming labels 2026-08-02 18:59:08 -04:00
Sign in to join this conversation.