Skip to content

Commit bec4a24

Browse files
melverpaulmckrcu
authored andcommitted
kcsan: Test support for compound instrumentation
Changes kcsan-test module to support checking reports that include compound instrumentation. Since we should not fail the test if this support is unavailable, we have to add a config variable that the test can use to decide what to check for. Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Marco Elver <elver@google.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
1 parent 9d1335c commit bec4a24

2 files changed

Lines changed: 56 additions & 14 deletions

File tree

kernel/kcsan/kcsan-test.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
#include <linux/types.h>
2828
#include <trace/events/printk.h>
2929

30+
#ifdef CONFIG_CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
31+
#define __KCSAN_ACCESS_RW(alt) (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
32+
#else
33+
#define __KCSAN_ACCESS_RW(alt) (alt)
34+
#endif
35+
3036
/* Points to current test-case memory access "kernels". */
3137
static void (*access_kernels[2])(void);
3238

@@ -186,20 +192,21 @@ static bool report_matches(const struct expect_report *r)
186192

187193
/* Access 1 & 2 */
188194
for (i = 0; i < 2; ++i) {
195+
const int ty = r->access[i].type;
189196
const char *const access_type =
190-
(r->access[i].type & KCSAN_ACCESS_ASSERT) ?
191-
((r->access[i].type & KCSAN_ACCESS_WRITE) ?
192-
"assert no accesses" :
193-
"assert no writes") :
194-
((r->access[i].type & KCSAN_ACCESS_WRITE) ?
195-
"write" :
196-
"read");
197+
(ty & KCSAN_ACCESS_ASSERT) ?
198+
((ty & KCSAN_ACCESS_WRITE) ?
199+
"assert no accesses" :
200+
"assert no writes") :
201+
((ty & KCSAN_ACCESS_WRITE) ?
202+
((ty & KCSAN_ACCESS_COMPOUND) ?
203+
"read-write" :
204+
"write") :
205+
"read");
197206
const char *const access_type_aux =
198-
(r->access[i].type & KCSAN_ACCESS_ATOMIC) ?
199-
" (marked)" :
200-
((r->access[i].type & KCSAN_ACCESS_SCOPED) ?
201-
" (scoped)" :
202-
"");
207+
(ty & KCSAN_ACCESS_ATOMIC) ?
208+
" (marked)" :
209+
((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : "");
203210

204211
if (i == 1) {
205212
/* Access 2 */
@@ -277,6 +284,12 @@ static noinline void test_kernel_write_atomic(void)
277284
WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1);
278285
}
279286

287+
static noinline void test_kernel_atomic_rmw(void)
288+
{
289+
/* Use builtin, so we can set up the "bad" atomic/non-atomic scenario. */
290+
__atomic_fetch_add(&test_var, 1, __ATOMIC_RELAXED);
291+
}
292+
280293
__no_kcsan
281294
static noinline void test_kernel_write_uninstrumented(void) { test_var++; }
282295

@@ -439,8 +452,8 @@ static void test_concurrent_races(struct kunit *test)
439452
const struct expect_report expect = {
440453
.access = {
441454
/* NULL will match any address. */
442-
{ test_kernel_rmw_array, NULL, 0, KCSAN_ACCESS_WRITE },
443-
{ test_kernel_rmw_array, NULL, 0, 0 },
455+
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
456+
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) },
444457
},
445458
};
446459
static const struct expect_report never = {
@@ -629,6 +642,29 @@ static void test_read_plain_atomic_write(struct kunit *test)
629642
KUNIT_EXPECT_TRUE(test, match_expect);
630643
}
631644

645+
/* Test that atomic RMWs generate correct report. */
646+
__no_kcsan
647+
static void test_read_plain_atomic_rmw(struct kunit *test)
648+
{
649+
const struct expect_report expect = {
650+
.access = {
651+
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
652+
{ test_kernel_atomic_rmw, &test_var, sizeof(test_var),
653+
KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC },
654+
},
655+
};
656+
bool match_expect = false;
657+
658+
if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS))
659+
return;
660+
661+
begin_test_checks(test_kernel_read, test_kernel_atomic_rmw);
662+
do {
663+
match_expect = report_matches(&expect);
664+
} while (!end_test_checks(match_expect));
665+
KUNIT_EXPECT_TRUE(test, match_expect);
666+
}
667+
632668
/* Zero-sized accesses should never cause data race reports. */
633669
__no_kcsan
634670
static void test_zero_size_access(struct kunit *test)
@@ -942,6 +978,7 @@ static struct kunit_case kcsan_test_cases[] = {
942978
KCSAN_KUNIT_CASE(test_write_write_struct_part),
943979
KCSAN_KUNIT_CASE(test_read_atomic_write_atomic),
944980
KCSAN_KUNIT_CASE(test_read_plain_atomic_write),
981+
KCSAN_KUNIT_CASE(test_read_plain_atomic_rmw),
945982
KCSAN_KUNIT_CASE(test_zero_size_access),
946983
KCSAN_KUNIT_CASE(test_data_race),
947984
KCSAN_KUNIT_CASE(test_assert_exclusive_writer),

lib/Kconfig.kcsan

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ menuconfig KCSAN
4040

4141
if KCSAN
4242

43+
# Compiler capabilities that should not fail the test if they are unavailable.
44+
config CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
45+
def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=thread -mllvm -tsan-compound-read-before-write=1)) || \
46+
(CC_IS_GCC && $(cc-option,-fsanitize=thread --param tsan-compound-read-before-write=1))
47+
4348
config KCSAN_VERBOSE
4449
bool "Show verbose reports with more information about system state"
4550
depends on PROVE_LOCKING

0 commit comments

Comments
 (0)