Skip to content

Commit 359a376

Browse files
Uriel Guajardoshuahkh
authored andcommitted
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 83c4e7a ("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 <[email protected]> Signed-off-by: Daniel Latypov <[email protected]> Signed-off-by: Uriel Guajardo <[email protected]> Reviewed-by: Alan Maguire <[email protected]> Reviewed-by: Brendan Higgins <[email protected]> Signed-off-by: Shuah Khan <[email protected]>
1 parent 9854781 commit 359a376

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

include/kunit/test-bug.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
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 <[email protected]>
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 */

lib/kunit/test.c

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <kunit/test.h>
10+
#include <kunit/test-bug.h>
1011
#include <linux/kernel.h>
1112
#include <linux/kref.h>
1213
#include <linux/sched/debug.h>
@@ -16,6 +17,40 @@
1617
#include "string-stream.h"
1718
#include "try-catch-impl.h"
1819

20+
#if IS_BUILTIN(CONFIG_KUNIT)
21+
/*
22+
* Fail the current test and print an error message to the log.
23+
*/
24+
void __kunit_fail_current_test(const char *file, int line, const char *fmt, ...)
25+
{
26+
va_list args;
27+
int len;
28+
char *buffer;
29+
30+
if (!current->kunit_test)
31+
return;
32+
33+
kunit_set_failure(current->kunit_test);
34+
35+
/* kunit_err() only accepts literals, so evaluate the args first. */
36+
va_start(args, fmt);
37+
len = vsnprintf(NULL, 0, fmt, args) + 1;
38+
va_end(args);
39+
40+
buffer = kunit_kmalloc(current->kunit_test, len, GFP_KERNEL);
41+
if (!buffer)
42+
return;
43+
44+
va_start(args, fmt);
45+
vsnprintf(buffer, len, fmt, args);
46+
va_end(args);
47+
48+
kunit_err(current->kunit_test, "%s:%d: %s", file, line, buffer);
49+
kunit_kfree(current->kunit_test, buffer);
50+
}
51+
EXPORT_SYMBOL_GPL(__kunit_fail_current_test);
52+
#endif
53+
1954
/*
2055
* Append formatted message to log, size of which is limited to
2156
* KUNIT_LOG_SIZE bytes (including null terminating byte).
@@ -273,9 +308,7 @@ static void kunit_try_run_case(void *data)
273308
struct kunit_suite *suite = ctx->suite;
274309
struct kunit_case *test_case = ctx->test_case;
275310

276-
#if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT))
277311
current->kunit_test = test;
278-
#endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT) */
279312

280313
/*
281314
* kunit_run_case_internal may encounter a fatal error; if it does,
@@ -624,9 +657,7 @@ void kunit_cleanup(struct kunit *test)
624657
spin_unlock(&test->lock);
625658
kunit_remove_resource(test, res);
626659
}
627-
#if (IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT))
628660
current->kunit_test = NULL;
629-
#endif /* IS_ENABLED(CONFIG_KASAN) && IS_ENABLED(CONFIG_KUNIT)*/
630661
}
631662
EXPORT_SYMBOL_GPL(kunit_cleanup);
632663

0 commit comments

Comments
 (0)