forked from Minki/linux
kcsan: test: Match reordered or normal accesses
Due to reordering accesses with weak memory modeling, any access can now appear as "(reordered)". Match any permutation of accesses if CONFIG_KCSAN_WEAK_MEMORY=y, so that we effectively match an access if it is denoted "(reordered)" or not. Signed-off-by: Marco Elver <elver@google.com> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
82eb6911d9
commit
7310bd1f3e
@ -151,7 +151,7 @@ struct expect_report {
|
||||
|
||||
/* Check observed report matches information in @r. */
|
||||
__no_kcsan
|
||||
static bool report_matches(const struct expect_report *r)
|
||||
static bool __report_matches(const struct expect_report *r)
|
||||
{
|
||||
const bool is_assert = (r->access[0].type | r->access[1].type) & KCSAN_ACCESS_ASSERT;
|
||||
bool ret = false;
|
||||
@ -253,6 +253,40 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline const struct expect_report *
|
||||
__report_set_scoped(struct expect_report *r, int accesses)
|
||||
{
|
||||
BUILD_BUG_ON(accesses > 3);
|
||||
|
||||
if (accesses & 1)
|
||||
r->access[0].type |= KCSAN_ACCESS_SCOPED;
|
||||
else
|
||||
r->access[0].type &= ~KCSAN_ACCESS_SCOPED;
|
||||
|
||||
if (accesses & 2)
|
||||
r->access[1].type |= KCSAN_ACCESS_SCOPED;
|
||||
else
|
||||
r->access[1].type &= ~KCSAN_ACCESS_SCOPED;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
__no_kcsan
|
||||
static bool report_matches_any_reordered(struct expect_report *r)
|
||||
{
|
||||
return __report_matches(__report_set_scoped(r, 0)) ||
|
||||
__report_matches(__report_set_scoped(r, 1)) ||
|
||||
__report_matches(__report_set_scoped(r, 2)) ||
|
||||
__report_matches(__report_set_scoped(r, 3));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KCSAN_WEAK_MEMORY
|
||||
/* Due to reordering accesses, any access may appear as "(reordered)". */
|
||||
#define report_matches report_matches_any_reordered
|
||||
#else
|
||||
#define report_matches __report_matches
|
||||
#endif
|
||||
|
||||
/* ===== Test kernels ===== */
|
||||
|
||||
static long test_sink;
|
||||
@ -438,13 +472,13 @@ static noinline void test_kernel_xor_1bit(void)
|
||||
__no_kcsan
|
||||
static void test_basic(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_write, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
},
|
||||
};
|
||||
static const struct expect_report never = {
|
||||
struct expect_report never = {
|
||||
.access = {
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
@ -469,14 +503,14 @@ static void test_basic(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_concurrent_races(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
/* NULL will match any address. */
|
||||
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
|
||||
{ test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) },
|
||||
},
|
||||
};
|
||||
static const struct expect_report never = {
|
||||
struct expect_report never = {
|
||||
.access = {
|
||||
{ test_kernel_rmw_array, NULL, 0, 0 },
|
||||
{ test_kernel_rmw_array, NULL, 0, 0 },
|
||||
@ -498,13 +532,13 @@ static void test_concurrent_races(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_novalue_change(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect_rw = {
|
||||
struct expect_report expect_rw = {
|
||||
.access = {
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
},
|
||||
};
|
||||
const struct expect_report expect_ww = {
|
||||
struct expect_report expect_ww = {
|
||||
.access = {
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
@ -530,13 +564,13 @@ static void test_novalue_change(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_novalue_change_exception(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect_rw = {
|
||||
struct expect_report expect_rw = {
|
||||
.access = {
|
||||
{ test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
},
|
||||
};
|
||||
const struct expect_report expect_ww = {
|
||||
struct expect_report expect_ww = {
|
||||
.access = {
|
||||
{ test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write_nochange_rcu, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
@ -556,7 +590,7 @@ static void test_novalue_change_exception(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_unknown_origin(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
{ NULL },
|
||||
@ -578,7 +612,7 @@ static void test_unknown_origin(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_write_write_assume_atomic(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_write, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
@ -604,7 +638,7 @@ static void test_write_write_assume_atomic(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_write_write_struct(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
@ -626,7 +660,7 @@ static void test_write_write_struct(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_write_write_struct_part(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write_struct_part, &test_struct.val[3], sizeof(test_struct.val[3]), KCSAN_ACCESS_WRITE },
|
||||
@ -658,7 +692,7 @@ static void test_read_atomic_write_atomic(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_read_plain_atomic_write(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
{ test_kernel_write_atomic, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ATOMIC },
|
||||
@ -679,7 +713,7 @@ static void test_read_plain_atomic_write(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_read_plain_atomic_rmw(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
{ test_kernel_atomic_rmw, &test_var, sizeof(test_var),
|
||||
@ -701,13 +735,13 @@ static void test_read_plain_atomic_rmw(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_zero_size_access(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
},
|
||||
};
|
||||
const struct expect_report never = {
|
||||
struct expect_report never = {
|
||||
.access = {
|
||||
{ test_kernel_write_struct, &test_struct, sizeof(test_struct), KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_read_struct_zero_size, &test_struct.val[3], 0, 0 },
|
||||
@ -741,7 +775,7 @@ static void test_data_race(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_writer(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_assert_writer, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT },
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
@ -759,7 +793,7 @@ static void test_assert_exclusive_writer(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_access(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_assert_access, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
@ -777,19 +811,19 @@ static void test_assert_exclusive_access(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_access_writer(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect_access_writer = {
|
||||
struct expect_report expect_access_writer = {
|
||||
.access = {
|
||||
{ test_kernel_assert_access, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_assert_writer, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT },
|
||||
},
|
||||
};
|
||||
const struct expect_report expect_access_access = {
|
||||
struct expect_report expect_access_access = {
|
||||
.access = {
|
||||
{ test_kernel_assert_access, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE },
|
||||
{ test_kernel_assert_access, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE },
|
||||
},
|
||||
};
|
||||
const struct expect_report never = {
|
||||
struct expect_report never = {
|
||||
.access = {
|
||||
{ test_kernel_assert_writer, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT },
|
||||
{ test_kernel_assert_writer, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT },
|
||||
@ -813,7 +847,7 @@ static void test_assert_exclusive_access_writer(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_bits_change(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_assert_bits_change, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT },
|
||||
{ test_kernel_change_bits, &test_var, sizeof(test_var),
|
||||
@ -844,13 +878,13 @@ static void test_assert_exclusive_bits_nochange(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_writer_scoped(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect_start = {
|
||||
struct expect_report expect_start = {
|
||||
.access = {
|
||||
{ test_kernel_assert_writer_scoped, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_SCOPED },
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
},
|
||||
};
|
||||
const struct expect_report expect_inscope = {
|
||||
struct expect_report expect_inscope = {
|
||||
.access = {
|
||||
{ test_enter_scope, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_SCOPED },
|
||||
{ test_kernel_write_nochange, &test_var, sizeof(test_var), KCSAN_ACCESS_WRITE },
|
||||
@ -871,16 +905,16 @@ static void test_assert_exclusive_writer_scoped(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_assert_exclusive_access_scoped(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect_start1 = {
|
||||
struct expect_report expect_start1 = {
|
||||
.access = {
|
||||
{ test_kernel_assert_access_scoped, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_SCOPED },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
},
|
||||
};
|
||||
const struct expect_report expect_start2 = {
|
||||
struct expect_report expect_start2 = {
|
||||
.access = { expect_start1.access[0], expect_start1.access[0] },
|
||||
};
|
||||
const struct expect_report expect_inscope = {
|
||||
struct expect_report expect_inscope = {
|
||||
.access = {
|
||||
{ test_enter_scope, &test_var, sizeof(test_var), KCSAN_ACCESS_ASSERT | KCSAN_ACCESS_WRITE | KCSAN_ACCESS_SCOPED },
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
@ -985,7 +1019,7 @@ static void test_atomic_builtins(struct kunit *test)
|
||||
__no_kcsan
|
||||
static void test_1bit_value_change(struct kunit *test)
|
||||
{
|
||||
const struct expect_report expect = {
|
||||
struct expect_report expect = {
|
||||
.access = {
|
||||
{ test_kernel_read, &test_var, sizeof(test_var), 0 },
|
||||
{ test_kernel_xor_1bit, &test_var, sizeof(test_var), __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) },
|
||||
|
Loading…
Reference in New Issue
Block a user