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;