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.
Unified · Split
| @@ -27,6 +27,12 @@ · 26 unmodified lines | |||
| 27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
| 28 | #include <trace/events/printk.h> | 28 | #include <trace/events/printk.h> |
| 29 | 29 | ||
| 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 | |||
| 30 | /* Points to current test-case memory access "kernels". */ | 36 | /* Points to current test-case memory access "kernels". */ |
| 31 | static void (*access_kernels[2])(void); | 37 | static void (*access_kernels[2])(void); |
| 32 | 38 | ||
| @@ -186,20 +192,21 @@ static bool report_matches(const struct expect_report *r) · 153 unmodified lines | |||
| 186 | 192 | ||
| 187 | /* Access 1 & 2 */ | 193 | /* Access 1 & 2 */ |
| 188 | for (i = 0; i < 2; ++i) { | 194 | for (i = 0; i < 2; ++i) { |
| 195 | const int ty = r->access[i].type; | ||
| 189 | const char *const access_type = | 196 | const char *const access_type = |
| 190 | (r->access[i].type & KCSAN_ACCESS_ASSERT) ? | 197 | (ty & KCSAN_ACCESS_ASSERT) ? |
| 191 | ((r->access[i].type & KCSAN_ACCESS_WRITE) ? | 198 | ((ty & KCSAN_ACCESS_WRITE) ? |
| 192 | "assert no accesses" : | 199 | "assert no accesses" : |
| 193 | "assert no writes") : | 200 | "assert no writes") : |
| 194 | ((r->access[i].type & KCSAN_ACCESS_WRITE) ? | 201 | ((ty & KCSAN_ACCESS_WRITE) ? |
| 195 | "write" : | 202 | ((ty & KCSAN_ACCESS_COMPOUND) ? |
| 196 | "read"); | 203 | "read-write" : |
| 204 | "write") : | ||
| 205 | "read"); | ||
| 197 | const char *const access_type_aux = | 206 | const char *const access_type_aux = |
| 198 | (r->access[i].type & KCSAN_ACCESS_ATOMIC) ? | 207 | (ty & KCSAN_ACCESS_ATOMIC) ? |
| 199 | " (marked)" : | 208 | " (marked)" : |
| 200 | ((r->access[i].type & KCSAN_ACCESS_SCOPED) ? | 209 | ((ty & KCSAN_ACCESS_SCOPED) ? " (scoped)" : ""); |
| 201 | " (scoped)" : | ||
| 202 | ""); | ||
| 203 | 210 | ||
| 204 | if (i == 1) { | 211 | if (i == 1) { |
| 205 | /* Access 2 */ | 212 | /* Access 2 */ |
| @@ -277,6 +284,12 @@ static noinline void test_kernel_write_atomic(void) · 71 unmodified lines | |||
| 277 | WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1); | 284 | WRITE_ONCE(test_var, READ_ONCE_NOCHECK(test_sink) + 1); |
| 278 | } | 285 | } |
| 279 | 286 | ||
| 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 | |||
| 280 | __no_kcsan | 293 | __no_kcsan |
| 281 | static noinline void test_kernel_write_uninstrumented(void) { test_var++; } | 294 | static noinline void test_kernel_write_uninstrumented(void) { test_var++; } |
| 282 | 295 | ||
| @@ -439,8 +452,8 @@ static void test_concurrent_races(struct kunit *test) · 156 unmodified lines | |||
| 439 | const struct expect_report expect = { | 452 | const struct expect_report expect = { |
| 440 | .access = { | 453 | .access = { |
| 441 | /* NULL will match any address. */ | 454 | /* NULL will match any address. */ |
| 442 | { test_kernel_rmw_array, NULL, 0, KCSAN_ACCESS_WRITE }, | 455 | { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(KCSAN_ACCESS_WRITE) }, |
| 443 | { test_kernel_rmw_array, NULL, 0, 0 }, | 456 | { test_kernel_rmw_array, NULL, 0, __KCSAN_ACCESS_RW(0) }, |
| 444 | }, | 457 | }, |
| 445 | }; | 458 | }; |
| 446 | static const struct expect_report never = { | 459 | static const struct expect_report never = { |
| @@ -629,6 +642,29 @@ static void test_read_plain_atomic_write(struct kunit *test) · 182 unmodified lines | |||
| 629 | KUNIT_EXPECT_TRUE(test, match_expect); | 642 | KUNIT_EXPECT_TRUE(test, match_expect); |
| 630 | } | 643 | } |
| 631 | 644 | ||
| 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 | |||
| 632 | /* Zero-sized accesses should never cause data race reports. */ | 668 | /* Zero-sized accesses should never cause data race reports. */ |
| 633 | __no_kcsan | 669 | __no_kcsan |
| 634 | static void test_zero_size_access(struct kunit *test) | 670 | static void test_zero_size_access(struct kunit *test) |
| @@ -942,6 +978,7 @@ static struct kunit_case kcsan_test_cases[] = { · 307 unmodified lines | |||
| 942 | KCSAN_KUNIT_CASE(test_write_write_struct_part), | 978 | KCSAN_KUNIT_CASE(test_write_write_struct_part), |
| 943 | KCSAN_KUNIT_CASE(test_read_atomic_write_atomic), | 979 | KCSAN_KUNIT_CASE(test_read_atomic_write_atomic), |
| 944 | KCSAN_KUNIT_CASE(test_read_plain_atomic_write), | 980 | KCSAN_KUNIT_CASE(test_read_plain_atomic_write), |
| 981 | KCSAN_KUNIT_CASE(test_read_plain_atomic_rmw), | ||
| 945 | KCSAN_KUNIT_CASE(test_zero_size_access), | 982 | KCSAN_KUNIT_CASE(test_zero_size_access), |
| 946 | KCSAN_KUNIT_CASE(test_data_race), | 983 | KCSAN_KUNIT_CASE(test_data_race), |
| 947 | KCSAN_KUNIT_CASE(test_assert_exclusive_writer), | 984 | KCSAN_KUNIT_CASE(test_assert_exclusive_writer), |
| @@ -40,6 +40,11 @@ menuconfig KCSAN · 39 unmodified lines | |||
| 40 | 40 | ||
| 41 | if KCSAN | 41 | if KCSAN |
| 42 | 42 | ||
| 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 | |||
| 43 | config KCSAN_VERBOSE | 48 | config KCSAN_VERBOSE |
| 44 | bool "Show verbose reports with more information about system state" | 49 | bool "Show verbose reports with more information about system state" |
| 45 | depends on PROVE_LOCKING | 50 | depends on PROVE_LOCKING |