The status-code ownership notes described work that has landed. That record belongs in the commit that made the change and in the comments around the code it constrains, not in a file whose purpose is naming what is left. Keeps the six open items and the two unrelated pre-existing issues, and promotes the missing sanitizer run to the top: mutation testing found an out-of-bounds probe whose failure mode was a silent BSS write, which no assertion-based test was positioned to catch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3.4 KiB
TODO
Working notes for libakerror. Outstanding items only.
1. The test suite has no sanitizer run
Mutation testing caught an out-of-bounds probe in the status-name hash table that the suite could not: the failure mode was a write into adjacent BSS, which does not crash, so every test still passed. Sharpening one test closed that instance, but ASan would have caught the whole class directly and independently of how sharp the assertions are.
Add a -fsanitize=address,undefined build to .gitea/workflows/ci.yaml, or a
CMake option alongside AKERR_COVERAGE. This is the highest-value item here: it
covers the whole library, not just the registry, and the library's fixed pools
and manual buffer arithmetic are exactly what it is good at.
2. HANDLE-level status aliasing is still undetectable
Two components can compile the same integer into a case label without ever
reserving a range or registering a name, and nothing sees it. Ownership
enforcement covers naming, which is the part the library mediates; the case
label never reaches it.
Closing this needs the if/else if handler ladder — rewriting
PROCESS/HANDLE/HANDLE_GROUP/HANDLE_DEFAULT/FINISH so status matching
is not restricted to integer constant expressions. That would also allow
matching on ranges or predicates, and would let a handler resolve a code through
its owner. It touches the most load-bearing code in the library and every
consumer's error handling at once, so it wants its own change.
Note it would not by itself fix the "don't use CATCH or FAIL_*_BREAK
inside a loop" hazard: that comes from exiting via break, not from switch.
3. No registry introspection
There is no way to ask who owns a status, or to enumerate reservations. The "coordinate ranges at the dependency-stack level" advice in README.md therefore has no tooling behind it.
A read-only accessor plus a dump through akerr_log_method would let a startup
self-check or a CI job print the whole map for a linked stack. Cheap, additive,
and the natural next step for multi-component adoption.
4. No way to release a reservation
A plugin host that dlopens many distinct plugins over a process lifetime
accumulates ranges until the table fills. Reloading the same plugin is fine —
an identical repeat by the same owner is idempotent.
5. The registry is not thread safe
Global mutable state, no locking, and akerr_status_name_count++ is not atomic.
Currently documented as an initialization-time-only API rather than enforced. If
components start initializing on separate threads this needs either a lock or a
documented once-per-process init barrier.
6. Deprecate the two-argument name-registration path
akerr_name_for_status(status, name) cannot identify its caller, so it can only
check that some reservation covers the status, not that the caller owns it. It
exists for migration. Once consumers have moved to
akerr_register_status_name(), make the set path a no-op or remove it and leave
akerr_name_for_status() as pure lookup.
Unrelated pre-existing issues
- The
AKERR_USE_STDLIB=OFFbuild does not compile at all:bool,PATH_MAXandNULLare used unconditionally but only included under the stdlib branch. The README's dependency list states what a replacement must provide, but the header still needs its includes untangled for that configuration to work. CMakeLists.txtsetsmain_lib_destfromMY_LIBRARY_VERSION, which is never defined and never read. Dead line.