forked from luck/tmp_suning_uos_patched
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>
This commit is contained in:
parent
9d1335cc1e
commit
bec4a24748
|
@ -27,6 +27,12 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <trace/events/printk.h>
|
#include <trace/events/printk.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
|
||||||
|
#define __KCSAN_ACCESS_RW(alt) (KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE)
|
||||||
|
#else
|
||||||
|
#define __KCSAN_ACCESS_RW(alt) (alt)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Points to current test-case memory access "kernels". */
|
/* Points to current test-case memory access "kernels". */
|
||||||
static void (*access_kernels[2])(void);
|
static void (*access_kernels[2])(void);
|
||||||
|
|
||||||
|
@ -186,20 +192,21 @@ static bool report_matches(const struct expect_report *r)
|
||||||
|
|
||||||
/* Access 1 & 2 */
|
/* Access 1 & 2 */
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 2; ++i) {
|
||||||
|
const int ty = r->access[i].type;
|
||||||
const char *const access_type =
|
const char *const access_type =
|
||||||
(r->access[i].type & KCSAN_ACCESS_ASSERT) ?
|
(ty & KCSAN_ACCESS_ASSERT) ?
|
||||||
((r->access[i].type & KCSAN_ACCESS_WRITE) ?
|
((ty & KCSAN_ACCESS_WRITE) ?
|
||||||
"assert no accesses" :
|
"assert no accesses" :
|
||||||
"assert no writes") :
|
"assert no writes") :
|
||||||
((r->access[i].type & KCSAN_ACCESS_WRITE) ?
|
((ty & KCSAN_ACCESS_WRITE) ?
|
||||||
"write" :
|
((ty & KCSAN_ACCESS_COMPOUND) ?
|
||||||
|
"read-write" :
|
||||||
|
"write") :
|
||||||
"read");
|
"read");
|
||||||
const char *const access_type_aux =
|
const char *const access_type_aux =
|
||||||
(r->access[i].type & KCSAN_ACCESS_ATOMIC) ?
|
(ty & KCSAN_ACCESS_ATOMIC) ?
|
||||||
" (marked)" :
|
" (marked)" :
|
||||||
((r->access[i].type & KCSAN_ACCESS_SCOPED) ?
|
((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : "");
|
||||||
" (scoped)" :
|
|
||||||
"");
|
|
||||||
|
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
/* Access 2 */
|
/* Access 2 */
|
||||||
|
@ -277,6 +284,12 @@ static noinline void test_kernel_write_atomic(void)
|
||||||
WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1);
|
WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static noinline void test_kernel_atomic_rmw(void)
|
||||||
|
{
|
||||||
|
/* Use builtin, so we can set up the "bad" atomic/non-atomic scenario. */
|
||||||
|
__atomic_fetch_add(&test_var, 1, __ATOMIC_RELAXED);
|
||||||
|
}
|
||||||
|
|
||||||
__no_kcsan
|
__no_kcsan
|
||||||
static noinline void test_kernel_write_uninstrumented(void) { test_var++; }
|
static noinline void test_kernel_write_uninstrumented(void) { test_var++; }
|
||||||
|
|
||||||
|
@ -439,8 +452,8 @@ static void test_concurrent_races(struct kunit *test)
|
||||||
const struct expect_report expect = {
|
const struct expect_report expect = {
|
||||||
.access = {
|
.access = {
|
||||||
/* NULL will match any address. */
|
/* NULL will match any address. */
|
||||||
{ test_kernel_rmw_array, NULL, 0, KCSAN_ACCESS_WRITE },
|
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
|
||||||
{ test_kernel_rmw_array, NULL, 0, 0 },
|
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) },
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
static const struct expect_report never = {
|
static const struct expect_report never = {
|
||||||
|
@ -629,6 +642,29 @@ static void test_read_plain_atomic_write(struct kunit *test)
|
||||||
KUNIT_EXPECT_TRUE(test, match_expect);
|
KUNIT_EXPECT_TRUE(test, match_expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test that atomic RMWs generate correct report. */
|
||||||
|
__no_kcsan
|
||||||
|
static void test_read_plain_atomic_rmw(struct kunit *test)
|
||||||
|
{
|
||||||
|
const struct expect_report expect = {
|
||||||
|
.access = {
|
||||||
|
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||||
|
{ test_kernel_atomic_rmw, &test_var, sizeof(test_var),
|
||||||
|
KCSAN_ACCESS_COMPOUND | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
bool match_expect = false;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_KCSAN_IGNORE_ATOMICS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
begin_test_checks(test_kernel_read, test_kernel_atomic_rmw);
|
||||||
|
do {
|
||||||
|
match_expect = report_matches(&expect);
|
||||||
|
} while (!end_test_checks(match_expect));
|
||||||
|
KUNIT_EXPECT_TRUE(test, match_expect);
|
||||||
|
}
|
||||||
|
|
||||||
/* Zero-sized accesses should never cause data race reports. */
|
/* Zero-sized accesses should never cause data race reports. */
|
||||||
__no_kcsan
|
__no_kcsan
|
||||||
static void test_zero_size_access(struct kunit *test)
|
static void test_zero_size_access(struct kunit *test)
|
||||||
|
@ -942,6 +978,7 @@ static struct kunit_case kcsan_test_cases[] = {
|
||||||
KCSAN_KUNIT_CASE(test_write_write_struct_part),
|
KCSAN_KUNIT_CASE(test_write_write_struct_part),
|
||||||
KCSAN_KUNIT_CASE(test_read_atomic_write_atomic),
|
KCSAN_KUNIT_CASE(test_read_atomic_write_atomic),
|
||||||
KCSAN_KUNIT_CASE(test_read_plain_atomic_write),
|
KCSAN_KUNIT_CASE(test_read_plain_atomic_write),
|
||||||
|
KCSAN_KUNIT_CASE(test_read_plain_atomic_rmw),
|
||||||
KCSAN_KUNIT_CASE(test_zero_size_access),
|
KCSAN_KUNIT_CASE(test_zero_size_access),
|
||||||
KCSAN_KUNIT_CASE(test_data_race),
|
KCSAN_KUNIT_CASE(test_data_race),
|
||||||
KCSAN_KUNIT_CASE(test_assert_exclusive_writer),
|
KCSAN_KUNIT_CASE(test_assert_exclusive_writer),
|
||||||
|
|
|
@ -40,6 +40,11 @@ menuconfig KCSAN
|
||||||
|
|
||||||
if KCSAN
|
if KCSAN
|
||||||
|
|
||||||
|
# Compiler capabilities that should not fail the test if they are unavailable.
|
||||||
|
config CC_HAS_TSAN_COMPOUND_READ_BEFORE_WRITE
|
||||||
|
def_bool (CC_IS_CLANG && $(cc-option,-fsanitize=thread -mllvm -tsan-compound-read-before-write=1)) || \
|
||||||
|
(CC_IS_GCC && $(cc-option,-fsanitize=thread --param tsan-compound-read-before-write=1))
|
||||||
|
|
||||||
config KCSAN_VERBOSE
|
config KCSAN_VERBOSE
|
||||||
bool "Show verbose reports with more information about system state"
|
bool "Show verbose reports with more information about system state"
|
||||||
depends on PROVE_LOCKING
|
depends on PROVE_LOCKING
|
||||||
|
|
Loading…
Reference in New Issue
Block a user