Commit 56778b49 authored by David Gow's avatar David Gow Committed by Shuah Khan

kunit: Add a macro to wrap a deferred action function

KUnit's deferred action API accepts a void(*)(void *) function pointer
which is called when the test is exited. However, we very frequently
want to use existing functions which accept a single pointer, but which
may not be of type void*. While this is probably dodgy enough to be on
the wrong side of the C standard, it's been often used for similar
callbacks, and gcc's -Wcast-function-type seems to ignore cases where
the only difference is the type of the argument, assuming it's
compatible (i.e., they're both pointers to data).

However, clang 16 has introduced -Wcast-function-type-strict, which no
longer permits any deviation in function pointer type. This seems to be
because it'd break CFI, which validates the type of function calls.

This rather ruins our attempts to cast functions to defer them, and
leaves us with a few options. The one we've chosen is to implement a
macro which will generate a wrapper function which accepts a void*, and
casts the argument to the appropriate type.

For example, if you were trying to wrap:
void foo_close(struct foo *handle);
you could use:
KUNIT_DEFINE_ACTION_WRAPPER(kunit_action_foo_close,
			    foo_close,
			    struct foo *);

This would create a new kunit_action_foo_close() function, of type
kunit_action_t, which could be passed into kunit_add_action() and
similar functions.

In addition to defining this macro, update KUnit and its tests to use
it.

Link: https://github.com/ClangBuiltLinux/linux/issues/1750Reviewed-by: default avatarNathan Chancellor <nathan@kernel.org>
Tested-by: default avatarNathan Chancellor <nathan@kernel.org>
Acked-by: default avatarDaniel Vetter <daniel@ffwll.ch>
Reviewed-by: default avatarMaxime Ripard <mripard@kernel.org>
Signed-off-by: default avatarDavid Gow <davidgow@google.com>
Signed-off-by: default avatarShuah Khan <skhan@linuxfoundation.org>
parent ceb6a6f0
...@@ -651,12 +651,16 @@ For example: ...@@ -651,12 +651,16 @@ For example:
} }
Note that, for functions like device_unregister which only accept a single Note that, for functions like device_unregister which only accept a single
pointer-sized argument, it's possible to directly cast that function to pointer-sized argument, it's possible to automatically generate a wrapper
a ``kunit_action_t`` rather than writing a wrapper function, for example: with the ``KUNIT_DEFINE_ACTION_WRAPPER()`` macro, for example:
.. code-block:: C .. code-block:: C
kunit_add_action(test, (kunit_action_t *)&device_unregister, &dev); KUNIT_DEFINE_ACTION_WRAPPER(device_unregister, device_unregister_wrapper, struct device *);
kunit_add_action(test, &device_unregister_wrapper, &dev);
You should do this in preference to manually casting to the ``kunit_action_t`` type,
as casting function pointers will break Control Flow Integrity (CFI).
``kunit_add_action`` can fail if, for example, the system is out of memory. ``kunit_add_action`` can fail if, for example, the system is out of memory.
You can use ``kunit_add_action_or_reset`` instead which runs the action You can use ``kunit_add_action_or_reset`` instead which runs the action
......
...@@ -390,6 +390,27 @@ void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); ...@@ -390,6 +390,27 @@ void kunit_remove_resource(struct kunit *test, struct kunit_resource *res);
/* A 'deferred action' function to be used with kunit_add_action. */ /* A 'deferred action' function to be used with kunit_add_action. */
typedef void (kunit_action_t)(void *); typedef void (kunit_action_t)(void *);
/**
* KUNIT_DEFINE_ACTION_WRAPPER() - Wrap a function for use as a deferred action.
*
* @wrapper: The name of the new wrapper function define.
* @orig: The original function to wrap.
* @arg_type: The type of the argument accepted by @orig.
*
* Defines a wrapper for a function which accepts a single, pointer-sized
* argument. This wrapper can then be passed to kunit_add_action() and
* similar. This should be used in preference to casting a function
* directly to kunit_action_t, as casting function pointers will break
* control flow integrity (CFI), leading to crashes.
*/
#define KUNIT_DEFINE_ACTION_WRAPPER(wrapper, orig, arg_type) \
static void wrapper(void *in) \
{ \
arg_type arg = (arg_type)in; \
orig(arg); \
}
/** /**
* kunit_add_action() - Call a function when the test ends. * kunit_add_action() - Call a function when the test ends.
* @test: Test case to associate the action with. * @test: Test case to associate the action with.
......
...@@ -538,10 +538,7 @@ static struct kunit_suite kunit_resource_test_suite = { ...@@ -538,10 +538,7 @@ static struct kunit_suite kunit_resource_test_suite = {
#if IS_BUILTIN(CONFIG_KUNIT_TEST) #if IS_BUILTIN(CONFIG_KUNIT_TEST)
/* This avoids a cast warning if kfree() is passed direct to kunit_add_action(). */ /* This avoids a cast warning if kfree() is passed direct to kunit_add_action(). */
static void kfree_wrapper(void *p) KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *);
{
kfree(p);
}
static void kunit_log_test(struct kunit *test) static void kunit_log_test(struct kunit *test)
{ {
......
...@@ -810,6 +810,8 @@ static struct notifier_block kunit_mod_nb = { ...@@ -810,6 +810,8 @@ static struct notifier_block kunit_mod_nb = {
}; };
#endif #endif
KUNIT_DEFINE_ACTION_WRAPPER(kfree_action_wrapper, kfree, const void *)
void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp) void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp)
{ {
void *data; void *data;
...@@ -819,7 +821,7 @@ void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp) ...@@ -819,7 +821,7 @@ void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp)
if (!data) if (!data)
return NULL; return NULL;
if (kunit_add_action_or_reset(test, (kunit_action_t *)kfree, data) != 0) if (kunit_add_action_or_reset(test, kfree_action_wrapper, data) != 0)
return NULL; return NULL;
return data; return data;
...@@ -831,7 +833,7 @@ void kunit_kfree(struct kunit *test, const void *ptr) ...@@ -831,7 +833,7 @@ void kunit_kfree(struct kunit *test, const void *ptr)
if (!ptr) if (!ptr)
return; return;
kunit_release_action(test, (kunit_action_t *)kfree, (void *)ptr); kunit_release_action(test, kfree_action_wrapper, (void *)ptr);
} }
EXPORT_SYMBOL_GPL(kunit_kfree); EXPORT_SYMBOL_GPL(kunit_kfree);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment