From 0d1abb4ced7812f7bd4b6418964d93bf6ef9f759 Mon Sep 17 00:00:00 2001 From: Ivan FB Date: Tue, 14 Jul 2026 14:31:42 +0200 Subject: [PATCH] fix(tests): ignore non-terminal RET_STALE_WARN in testCallback The shared result callback treated every code as an answer, so the 5s stale ping fired by the slow arm+ASan runner during the 50k-ref-alloc handler woke waitCallback with retCode=3 and let the test tear the context down while the handler was still running -- which in turn made destroyFFIContext err and left the event thread firing on a torn-down signal (the UBSan fireSync null deref). Honour the same contract the generated C/C++/Rust trampolines now follow: a progress ping is not a reply. Tests asserting on the pings use staleCallback instead. Co-Authored-By: Claude Opus 4.8 --- tests/unit/test_ffi_context.nim | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/unit/test_ffi_context.nim b/tests/unit/test_ffi_context.nim index 52c435f..09304e9 100644 --- a/tests/unit/test_ffi_context.nim +++ b/tests/unit/test_ffi_context.nim @@ -27,6 +27,12 @@ proc deinitCallbackData(d: var CallbackData) = proc testCallback( retCode: cint, msg: ptr cchar, len: csize_t, userData: pointer ) {.cdecl, gcsafe, raises: [].} = + # RET_STALE_WARN is a progress ping, not an answer: a slow handler (or a slow + # CI runner) trips it before the terminal code arrives. Waking `waitCallback` + # here would hand the test a non-terminal retCode and let it tear the context + # down mid-flight. Tests that assert on the pings use `staleCallback`. + if retCode == RET_STALE_WARN: + return let d = cast[ptr CallbackData](userData) acquire(d[].lock) d[].retCode = retCode