IGNORE() logs a context and never releases it, so every ignored failure leaks a pool slot #14

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

Source: found downstream: libakstdlib TODO.md §1.2, filed here while moving both trackers (at 5695061)

This defect was recorded only in a consumer's TODO file, never in this
repository's.
It is filed here because this is where the fix is.

include/akerror.tmpl.h:424-428:

#define IGNORE(__stmt)							\
    __akerr_last_ignored = __stmt;					\
    if ( __akerr_last_ignored != NULL ) {				\
	LOG_ERROR_WITH_MESSAGE(__akerr_last_ignored, "** IGNORED ERROR **"); \
    }

The macro assigns the context, logs it, and stops. The slot is never returned to
the pool
, so every IGNORE() on a failing call leaks one -- and after
AKERR_MAX_ARRAY_ERROR of them the pool is exhausted and ENSURE_ERROR_READY
calls exit(1). A process that ignores failures in a loop dies from ignoring
them.

The cost downstream, measured. libakstdlib's aksl_tree_iterate CLEANUP
block cannot use IGNORE() to drop a queue-drain failure and open-codes
log-then-release by hand instead
, with a comment saying why. Four lines that
should be one. libakgl uses IGNORE() freely in CLEANUP blocks, which is what
the macro is for, and each of those sites is a slot.

The fix is one RELEASE_ERROR in the macro, then the workaround downstream
comes out.

Worth deciding at the same time: whether __akerr_last_ignored should keep
pointing at a released context. It is a debugging aid, and after the fix it points
at a slot that may be reissued -- so either it becomes a copy of the status, or its
documentation says plainly that it is only valid until the next acquire.

Files: include/akerror.tmpl.h:424-428


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

**Source:** found downstream: libakstdlib TODO.md §1.2, filed here while moving both trackers (at 5695061) **This defect was recorded only in a consumer's TODO file, never in this repository's.** It is filed here because this is where the fix is. `include/akerror.tmpl.h:424-428`: ```c #define IGNORE(__stmt) \ __akerr_last_ignored = __stmt; \ if ( __akerr_last_ignored != NULL ) { \ LOG_ERROR_WITH_MESSAGE(__akerr_last_ignored, "** IGNORED ERROR **"); \ } ``` The macro assigns the context, logs it, and stops. **The slot is never returned to the pool**, so every `IGNORE()` on a failing call leaks one -- and after `AKERR_MAX_ARRAY_ERROR` of them the pool is exhausted and `ENSURE_ERROR_READY` calls `exit(1)`. **A process that ignores failures in a loop dies from ignoring them.** **The cost downstream, measured.** `libakstdlib`'s `aksl_tree_iterate` `CLEANUP` block cannot use `IGNORE()` to drop a queue-drain failure and **open-codes log-then-release by hand instead**, with a comment saying why. Four lines that should be one. libakgl uses `IGNORE()` freely in `CLEANUP` blocks, which is what the macro is for, and each of those sites is a slot. **The fix is one `RELEASE_ERROR` in the macro**, then the workaround downstream comes out. Worth deciding at the same time: whether `__akerr_last_ignored` should keep pointing at a released context. It is a debugging aid, and after the fix it points at a slot that may be reissued -- so either it becomes a copy of the status, or its documentation says plainly that it is only valid until the next acquire. **Files:** `include/akerror.tmpl.h:424-428` --- Filed by Tachikoma (Claude Code, Opus 5, 1M context)
tachikoma added this to the 2.0.x milestone 2026-08-02 18:59:15 -04:00
tachikoma added the defectblast-radius:highstatus::grooming labels 2026-08-02 18:59:15 -04:00
Sign in to join this conversation.