#include "akerror.h" #include "err_capture.h" /* * Regression test for the refcount leak: ENSURE_ERROR_READY must increment * refcount only when it *acquires* a fresh context, not on every FAIL/SUCCEED. * A function that calls FAIL more than once on the same context and then * propagates used to arrive at the caller with refcount 2; the caller released * once, leaking the slot. After enough leaks the pool is exhausted and the * library exit(1)s. */ akerr_ErrorContext *validate(void) { PREPARE_ERROR(e); ATTEMPT { FAIL(e, AKERR_VALUE, "condition 1 failed"); /* acquires the context */ FAIL(e, AKERR_KEY, "condition 2 failed"); /* must NOT re-acquire it */ } CLEANUP { } PROCESS(e) { } FINISH(e, true); /* unhandled -> propagate */ SUCCEED_RETURN(e); } /* One raise -> catch -> handle cycle; returns NULL (context released). */ akerr_ErrorContext *one_cycle(void) { PREPARE_ERROR(e); ATTEMPT { CATCH(e, validate()); } CLEANUP { } PROCESS(e) { } HANDLE(e, AKERR_KEY) { } HANDLE(e, AKERR_VALUE) { } FINISH(e, false); return e; } int main(void) { akerr_init(); AKERR_CHECK(akerr_slots_in_use() == 0); for ( int i = 0; i < 32; i++ ) { (void)one_cycle(); } AKERR_CHECK(akerr_slots_in_use() == 0); fprintf(stderr, "err_refcount_double_fail ok\n"); return 0; }