Commit 64aefa555f for strongswan.org
commit 64aefa555fc211ced9be9ef977923b0c25e6d009
Author: Tobias Brunner <tobias@strongswan.org>
Date: Wed Oct 28 14:32:01 2026 +0100
test-runner: Abort when interrupted during library deinit
If we get interrupted during the deinitialization, we leave `lib` in
half-destroyed state. Calling `library_deinit()` again after
`siglongjmp()` is no good and would cause use-after-frees or double-frees
and initializing it later won't work either because `lib` was not set to
NULL. So the next test run would skip initialization and continue with
a half-destroyed `lib` object. To avoid that, we try to detect it and
just abort. We keep the timer armed to recover from deinit being stuck
somewhere (e.g. when canceling threads or on some lock that was not
released due to `siglongjmp()`), at least if it was not a timeout that
got us there in the first place. And while all runners currently pass
an init function, restructuring the if-statements also handles the case
if that wasn't the case. Note that similar issues with other library
deinit functions (as called by the runner init callbacks) are obviously
not covered by this change.
diff --git a/src/libstrongswan/tests/test_runner.c b/src/libstrongswan/tests/test_runner.c
index b557a74194..86fc3d1488 100644
--- a/src/libstrongswan/tests/test_runner.c
+++ b/src/libstrongswan/tests/test_runner.c
@@ -411,19 +411,34 @@ static bool post_test(test_runner_init_t init, bool check_leaks,
.name = name,
.i = i,
};
+ volatile bool deinit_called = FALSE;
- if (init)
+ if (test_restore_point())
{
- if (test_restore_point())
+ if (init)
{
init(FALSE);
}
- else
+ }
+ else
+ {
+ if (deinit_called && lib)
+ {
+ /* a timeout or critical signal was triggered during library deinit,
+ * which leaves it partially deinitialized (lib stays set) and we
+ * won't be able to initialize it again, so we abort to avoid
+ * undefined behavior */
+ fprintf(stderr, "\n%sTimeout/failure during library deinit%s\n",
+ TTY(RED), TTY(DEF));
+ abort();
+ }
+ if (!deinit_called)
{
thread_cleanup_popall();
+ deinit_called = TRUE;
library_deinit();
- return FALSE;
}
+ return FALSE;
}
if (check_leaks && lib->leak_detective)
{
@@ -431,6 +446,7 @@ static bool post_test(test_runner_init_t init, bool check_leaks,
(leak_detective_report_cb_t)report_leaks,
(leak_detective_summary_cb_t)sum_leaks, &data);
}
+ deinit_called = TRUE;
library_deinit();
*leaks = data.leaks;