Commit 869c7889 authored by Thomas Weißschuh's avatar Thomas Weißschuh Committed by Thomas Weißschuh
Browse files

selftests: harness: Stop using setjmp()/longjmp()



Usage of longjmp() was added to ensure that teardown is always run in
commit 63e6b2a4 ("selftests/harness: Run TEARDOWN for ASSERT failures")
However instead of calling longjmp() to the teardown handler it is easier to
just call the teardown handler directly from __bail().
Any potential duplicate teardown invocations are harmless as the actual
handler will only ever be executed once since
commit fff37bd3 ("selftests/harness: Fix fixture teardown").

Additionally this removes a incompatibility with nolibc,
which does not support setjmp()/longjmp().

Signed-off-by: default avatarThomas Weißschuh <thomas.weissschuh@linutronix.de>
Acked-by: default avatarShuah Khan <skhan@linuxfoundation.org>
Link: https://lore.kernel.org/r/20250505-nolibc-kselftest-harness-v4-12-ee4dd5257135@linutronix.de


Signed-off-by: default avatarThomas Weißschuh <linux@weissschuh.net>
parent f46ddc2c
Loading
Loading
Loading
Loading
+15 −30
Original line number Diff line number Diff line
@@ -67,7 +67,6 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <setjmp.h>

#include "kselftest.h"

@@ -178,9 +177,7 @@
		struct __test_metadata *_metadata, \
		struct __fixture_variant_metadata __attribute__((unused)) *variant) \
	{ \
		if (setjmp(_metadata->env) == 0) \
		test_name(_metadata); \
		__test_check_assert(_metadata); \
	} \
	static struct __test_metadata _##test_name##_object = \
		{ .name = #test_name, \
@@ -425,7 +422,6 @@
		} \
		_metadata->variant = variant->data; \
		_metadata->self = self; \
		if (setjmp(_metadata->env) == 0) { \
		/* _metadata and potentially self are shared with all forks. */ \
		child = fork(); \
		if (child == 0) { \
@@ -435,15 +431,12 @@
				_exit(0); \
			*_metadata->no_teardown = false; \
			fixture_name##_##test_name(_metadata, self, variant->data); \
			_metadata->teardown_fn(false, _metadata, self, variant->data); \
			_exit(0); \
		} else if (child < 0 || child != waitpid(child, &status, 0)) { \
			ksft_print_msg("ERROR SPAWNING TEST GRANDCHILD\n"); \
			_metadata->exit_code = KSFT_FAIL; \
		} \
		} \
		if (child == 0) { \
			_metadata->teardown_fn(false, _metadata, self, variant->data); \
			_exit(0); \
		} \
		_metadata->teardown_fn(true, _metadata, self, variant->data); \
		munmap(_metadata->no_teardown, sizeof(*_metadata->no_teardown)); \
		_metadata->no_teardown = NULL; \
@@ -456,7 +449,6 @@
			/* Forward signal to __wait_for_test(). */ \
			kill(getpid(), WTERMSIG(status)); \
		} \
		__test_check_assert(_metadata); \
	} \
	static void wrapper_##fixture_name##_##test_name##_teardown( \
		bool in_parent, struct __test_metadata *_metadata, \
@@ -927,7 +919,6 @@ struct __test_metadata {
	int timeout;	/* seconds to wait for test timeout */
	bool aborted;	/* stopped test due to failed ASSERT */
	bool *no_teardown; /* fixture needs teardown */
	jmp_buf env;	/* for exiting out of test early */
	void *self;
	const void *variant;
	struct __test_results *results;
@@ -963,19 +954,14 @@ static inline int __bail(int for_realz, struct __test_metadata *t)
{
	/* if this is ASSERT, return immediately. */
	if (for_realz) {
		t->aborted = true;
		longjmp(t->env, 1);
		if (t->teardown_fn)
			t->teardown_fn(false, t, t->self, t->variant);
		abort();
	}
	/* otherwise, end the for loop and continue. */
	return 0;
}

static inline void __test_check_assert(struct __test_metadata *t)
{
	if (t->aborted)
		abort();
}

static void __wait_for_test(struct __test_metadata *t)
{
	/*
@@ -1208,7 +1194,6 @@ static void __run_test(struct __fixture_metadata *f,
	t->trigger = 0;
	t->aborted = false;
	t->no_teardown = NULL;
	memset(t->env, 0, sizeof(t->env));
	memset(t->results->reason, 0, sizeof(t->results->reason));

	snprintf(test_name, sizeof(test_name), "%s%s%s.%s",