Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: support failure from dynamic analysis tools

Add a kunit_fail_current_test() function to fail the currently running
test, if any, with an error message.

This is largely intended for dynamic analysis tools like UBSAN and for
fakes.
E.g. say I had a fake ops struct for testing and I wanted my `free`
function to complain if it was called with an invalid argument, or
caught a double-free. Most return void and have no normal means of
signalling failure (e.g. super_operations, iommu_ops, etc.).

Key points:
* Always update current->kunit_test so anyone can use it.
* commit 83c4e7a0363b ("KUnit: KASAN Integration") only updated it for
CONFIG_KASAN=y

* Create a new header <kunit/test-bug.h> so non-test code doesn't have
to include all of <kunit/test.h> (e.g. lib/ubsan.c)

* Forward the file and line number to make it easier to track down
failures

* Declare the helper function for nice __printf() warnings about mismatched
format strings even when KUnit is not enabled.

Example output from kunit_fail_current_test("message"):
[15:19:34] [FAILED] example_simple_test
[15:19:34] # example_simple_test: initializing
[15:19:34] # example_simple_test: lib/kunit/kunit-example-test.c:24: message
[15:19:34] not ok 1 - example_simple_test

Fixed minor check patch with checkpatch --fix option:
Shuah Khan <skhan@linuxfoundation.org>

Signed-off-by: Daniel Latypov <dlatypov@google.com>
Signed-off-by: Uriel Guajardo <urielguajardo@google.com>
Reviewed-by: Alan Maguire <alan.maguire@oracle.com>
Reviewed-by: Brendan Higgins <brendanhiggins@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Uriel Guajardo and committed by
Shuah Khan
359a3760 9854781d

+64 -4
+29
include/kunit/test-bug.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * KUnit API allowing dynamic analysis tools to interact with KUnit tests 4 + * 5 + * Copyright (C) 2020, Google LLC. 6 + * Author: Uriel Guajardo <urielguajardo@google.com> 7 + */ 8 + 9 + #ifndef _KUNIT_TEST_BUG_H 10 + #define _KUNIT_TEST_BUG_H 11 + 12 + #define kunit_fail_current_test(fmt, ...) \ 13 + __kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__) 14 + 15 + #if IS_BUILTIN(CONFIG_KUNIT) 16 + 17 + extern __printf(3, 4) void __kunit_fail_current_test(const char *file, int line, 18 + const char *fmt, ...); 19 + 20 + #else 21 + 22 + static __printf(3, 4) void __kunit_fail_current_test(const char *file, int line, 23 + const char *fmt, ...) 24 + { 25 + } 26 + 27 + #endif 28 + 29 + #endif /* _KUNIT_TEST_BUG_H */
+35 -4
lib/kunit/test.c
··· 7 7 */ 8 8 9 9 #include <kunit/test.h> 10 + #include <kunit/test-bug.h> 10 11 #include <linux/kernel.h> 11 12 #include <linux/kref.h> 12 13 #include <linux/sched/debug.h> ··· 16 15 #include "debugfs.h" 17 16 #include "string-stream.h" 18 17 #include "try-catch-impl.h" 18 + 19 + #if IS_BUILTIN(CONFIG_KUNIT) 20 + /* 21 + * Fail the current test and print an error message to the log. 22 + */ 23 + void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...) 24 + { 25 + va_list args; 26 + int len; 27 + char *buffer; 28 + 29 + if (!current->kunit_test) 30 + return; 31 + 32 + kunit_set_failure(current->kunit_test); 33 + 34 + /* kunit_err() only accepts literals, so evaluate the args first. */ 35 + va_start(args, fmt); 36 + len = vsnprintf(NULL, 0, fmt, args) + 1; 37 + va_end(args); 38 + 39 + buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL); 40 + if (!buffer) 41 + return; 42 + 43 + va_start(args, fmt); 44 + vsnprintf(buffer, len, fmt, args); 45 + va_end(args); 46 + 47 + kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer); 48 + kunit_kfree(current->kunit_test, buffer); 49 + } 50 + EXPORT_SYMBOL_GPL(__kunit_fail_current_test); 51 + #endif 19 52 20 53 /* 21 54 * Append formatted message to log, size of which is limited to ··· 308 273 struct kunit_suite *suite = ctx->suite; 309 274 struct kunit_case *test_case = ctx->test_case; 310 275 311 - #if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)) 312 276 current->kunit_test = test; 313 - #endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT) */ 314 277 315 278 /* 316 279 * kunit_run_case_internal may encounter a fatal error; if it does, ··· 657 624 spin_unlock(&test->lock); 658 625 kunit_remove_resource(test, res); 659 626 } 660 - #if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)) 661 627 current->kunit_test = NULL; 662 - #endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)*/ 663 628 } 664 629 EXPORT_SYMBOL_GPL(kunit_cleanup); 665 630