Two memory-safety bugs in the macro core:
1. Refcount leak. ENSURE_ERROR_READY incremented refcount on every FAIL/SUCCEED
rather than only when it acquired a fresh context from the pool. A function
that FAILed a context more than once and then propagated arrived at its
caller with refcount 2; the caller released once, leaking the slot. After
AKERR_MAX_ARRAY_ERROR leaks the pool is exhausted and the library exit(1)s.
Move the increment inside the acquisition branch.
2. Stack-trace overflow. Each appended frame passed the full buffer length to
snprintf instead of the space remaining, and advanced the cursor by
snprintf's would-be return value, so a trace that filled the buffer wrote
past the end of stacktracebuf and ran the cursor out of bounds. Add
AKERR_STACKTRACE_APPEND, which bounds the write to the remaining space and
clamps the cursor advance.
Regression tests err_refcount_double_fail and err_stacktrace_bounds fail against
the old code (verified) and pass now. Full suite: 21/21, no warnings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AKERR_MAX_ERR_VALUE was AKERR_LAST_ERRNO_VALUE + 15, but the highest defined
code, AKERR_BADEXC, is + 17 (AKERR_NOT_IMPLEMENTED is + 16). akerr_name_for_status
rejects any status above the max, so those codes could never have a registered
name and the AKERR_BADEXC registration in akerr_init was dead code -- a gap
found by mutation testing. Bump the max to + 17.
- err_maxval: new test asserting the reserved AKERR_* range exceeds the number
of AKERR_* codes and that every code is individually indexable. Fails against
the old + 15 value (verified), guarding against regression.
- err_error_names: now also checks AKERR_BADEXC's name, which the fix makes
reachable.
Mutation score on src/error.c rises 71% -> 74%: the previously-dead BADEXC
registration and the name_for_status upper-bound check are now killable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>