From e86251f693e7b0b055eb46bbdfb669768a2ec695 Mon Sep 17 00:00:00 2001 From: Andreas Nordal <4992374+anordal@users.noreply.github.com> Date: Mon, 15 Jun 2026 22:11:02 +0200 Subject: [PATCH 1/2] Unittest: Fix catch_assert() for Glibc>=2.41 Makes tests not die of SIGABRT (#1339). I only suspect this to depend on Glibc version: I have not dug in to the Glibc code to verify it, and I can't rule out another library, but that's my nullhypothesis. Tested: * Opensuse Tumbleweed last time I contributed = Good * Ubuntu 24.04 (Glibc 2.39) = Good * OpenSuse Leap 16 (Glibc 2.40) = Good * Ubuntu 25.04 (Glibc 2.41) = Bad * Ubuntu 26.04 (Glibc 2.41) = Bad * Opensuse Tumbleweed now = Bad Hypothesis: Signals are "blocked" (as in put in a queue) while the signal handler runs to avoid recursion. Thus, longjumping out of the signal handler may steer away from the signal unblocking path, thus isn't really supposed to work. This is the minimal but suboptimal change: Unblock the signal. This can be done more elegantly with siglongjmp (next commit). --- test/unit-test/catch_assert.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/unit-test/catch_assert.h b/test/unit-test/catch_assert.h index acfc6b4202..6dc3088223 100644 --- a/test/unit-test/catch_assert.h +++ b/test/unit-test/catch_assert.h @@ -67,6 +67,12 @@ static void catchHandler_( int signal ) else \ { \ lcatch++; \ + sigset_t sigrid; \ + sigemptyset( &sigrid ); \ + sigaddset( &sigrid, SIGABRT ); \ + pthread_sigmask( \ + SIG_UNBLOCK, &sigrid, NULL \ + ); \ } \ sigaction( SIGABRT, &saveSa, NULL ); \ dup2( saveFd, 2 ); \ From 4dc07738d813786f659d637558c95ec762566655 Mon Sep 17 00:00:00 2001 From: Andreas Nordal <4992374+anordal@users.noreply.github.com> Date: Mon, 15 Jun 2026 23:18:10 +0200 Subject: [PATCH 2/2] catch_assert: Use siglongjmp instead of restoring signals manually A more proper fix for #1339 than the previous commit: siglongjmp also restores signal state. Also take the opportunity to minimize macro state, code and namespace footprint. --- test/unit-test/catch_assert.h | 68 +++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/test/unit-test/catch_assert.h b/test/unit-test/catch_assert.h index 6dc3088223..99b11697cd 100644 --- a/test/unit-test/catch_assert.h +++ b/test/unit-test/catch_assert.h @@ -37,47 +37,47 @@ #include #include -#ifndef CATCH_JMPBUF - #define CATCH_JMPBUF waypoint_ -#endif - -static jmp_buf CATCH_JMPBUF; +/* Global state apology: Sigaction offers no context. */ +static sigjmp_buf catch_waypoint; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-function" -static void catchHandler_( int signal ) +static void catch_rollBack( int signal ) +{ + siglongjmp( catch_waypoint, signal ); +} +static void catch_setSigabrtHandler( void ) +{ + struct sigaction sa = { 0 }; + + sa.sa_handler = catch_rollBack; + sigaction( SIGABRT, &sa, NULL ); +} +static int catch_saveStderr() +{ + int savedStderr = dup( 2 ); + + close( 2 ); + return savedStderr; +} +static void catch_restoreStderr( int savedStderr ) { - longjmp( CATCH_JMPBUF, signal ); + dup2( savedStderr, 2 ); + close( savedStderr ); } #pragma GCC diagnostic pop -#define catch_assert( x ) \ - do { \ - int ltry = 0, lcatch = 0; \ - int saveFd = dup( 2 ); \ - struct sigaction sa = { 0 }, saveSa; \ - sa.sa_handler = catchHandler_; \ - sigaction( SIGABRT, &sa, &saveSa ); \ - close( 2 ); \ - if( setjmp( CATCH_JMPBUF ) == 0 ) \ - { \ - ltry++; \ - x; \ - } \ - else \ - { \ - lcatch++; \ - sigset_t sigrid; \ - sigemptyset( &sigrid ); \ - sigaddset( &sigrid, SIGABRT ); \ - pthread_sigmask( \ - SIG_UNBLOCK, &sigrid, NULL \ - ); \ - } \ - sigaction( SIGABRT, &saveSa, NULL ); \ - dup2( saveFd, 2 ); \ - close( saveFd ); \ - TEST_ASSERT_EQUAL( ltry, lcatch ); \ +#define catch_assert( x ) \ + do { \ + int catch_stderr = catch_saveStderr(); \ + int catch_signal = sigsetjmp( catch_waypoint, 1 ); \ + if( catch_signal == 0 ) \ + { \ + catch_setSigabrtHandler(); \ + x; \ + } \ + catch_restoreStderr( catch_stderr ); \ + TEST_ASSERT_EQUAL( SIGABRT, catch_signal ); \ } while( 0 ) #endif /* ifndef CATCH_ASSERT_H_ */