1 | //===-- sanitizer_atomic_test.cpp -----------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file is a part of ThreadSanitizer/AddressSanitizer runtime. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | #include "sanitizer_common/sanitizer_atomic.h" |
13 | #include "gtest/gtest.h" |
14 | |
15 | #ifndef __has_extension |
16 | #define __has_extension(x) 0 |
17 | #endif |
18 | |
19 | #ifndef ATOMIC_LLONG_LOCK_FREE |
20 | # if __has_extension(c_atomic) || __has_extension(cxx_atomic) |
21 | # define ATOMIC_LLONG_LOCK_FREE __CLANG_ATOMIC_LLONG_LOCK_FREE |
22 | # elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) |
23 | # define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE |
24 | # else |
25 | # error Unsupported compiler. |
26 | # endif |
27 | #endif |
28 | |
29 | namespace __sanitizer { |
30 | |
31 | template<typename T> |
32 | struct ValAndMagic { |
33 | typename T::Type magic0; |
34 | T a; |
35 | typename T::Type magic1; |
36 | |
37 | static ValAndMagic<T> *sink; |
38 | }; |
39 | |
40 | template<typename T> |
41 | ValAndMagic<T> *ValAndMagic<T>::sink; |
42 | |
43 | template<typename T, memory_order load_mo, memory_order store_mo> |
44 | void CheckStoreLoad() { |
45 | typedef typename T::Type Type; |
46 | ValAndMagic<T> val; |
47 | // Prevent the compiler from scalarizing the struct. |
48 | ValAndMagic<T>::sink = &val; |
49 | // Ensure that surrounding memory is not overwritten. |
50 | val.magic0 = val.magic1 = (Type)-3; |
51 | for (u64 i = 0; i < 100; i++) { |
52 | // Generate a value that occupies all bytes of the variable. |
53 | u64 v = i; |
54 | v |= v << 8; |
55 | v |= v << 16; |
56 | v |= v << 32; |
57 | val.a.val_dont_use = (Type)v; |
58 | EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v); |
59 | val.a.val_dont_use = (Type)-1; |
60 | atomic_store(&val.a, (Type)v, store_mo); |
61 | EXPECT_EQ(val.a.val_dont_use, (Type)v); |
62 | } |
63 | EXPECT_EQ(val.magic0, (Type)-3); |
64 | EXPECT_EQ(val.magic1, (Type)-3); |
65 | } |
66 | |
67 | TEST(SanitizerCommon, AtomicStoreLoad) { |
68 | CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>(); |
69 | CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>(); |
70 | CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>(); |
71 | CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>(); |
72 | CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>(); |
73 | |
74 | CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>(); |
75 | CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>(); |
76 | CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>(); |
77 | CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>(); |
78 | CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>(); |
79 | |
80 | CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>(); |
81 | CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>(); |
82 | CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>(); |
83 | CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>(); |
84 | CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>(); |
85 | |
86 | // Avoid fallbacking to software emulated compiler atomics, that are usually |
87 | // provided by libatomic, which is not always present. |
88 | #if ATOMIC_LLONG_LOCK_FREE == 2 |
89 | CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>(); |
90 | CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>(); |
91 | CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>(); |
92 | CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>(); |
93 | CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>(); |
94 | #endif |
95 | |
96 | CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed> |
97 | (); |
98 | CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed> |
99 | (); |
100 | CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed> |
101 | (); |
102 | CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release> |
103 | (); |
104 | CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst> |
105 | (); |
106 | } |
107 | |
108 | // Clang crashes while compiling this test for Android: |
109 | // http://llvm.org/bugs/show_bug.cgi?id=15587 |
110 | #if !SANITIZER_ANDROID |
111 | template<typename T> |
112 | void CheckAtomicCompareExchange() { |
113 | typedef typename T::Type Type; |
114 | { |
115 | Type old_val = 42; |
116 | Type new_val = 24; |
117 | Type var = old_val; |
118 | EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val, |
119 | memory_order_relaxed)); |
120 | EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val, |
121 | memory_order_relaxed)); |
122 | EXPECT_EQ(new_val, old_val); |
123 | } |
124 | { |
125 | Type old_val = 42; |
126 | Type new_val = 24; |
127 | Type var = old_val; |
128 | EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val, |
129 | memory_order_relaxed)); |
130 | EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val, |
131 | memory_order_relaxed)); |
132 | EXPECT_EQ(new_val, old_val); |
133 | } |
134 | } |
135 | |
136 | TEST(SanitizerCommon, AtomicCompareExchangeTest) { |
137 | CheckAtomicCompareExchange<atomic_uint8_t>(); |
138 | CheckAtomicCompareExchange<atomic_uint16_t>(); |
139 | CheckAtomicCompareExchange<atomic_uint32_t>(); |
140 | #if ATOMIC_LLONG_LOCK_FREE == 2 |
141 | CheckAtomicCompareExchange<atomic_uint64_t>(); |
142 | #endif |
143 | CheckAtomicCompareExchange<atomic_uintptr_t>(); |
144 | } |
145 | #endif //!SANITIZER_ANDROID |
146 | |
147 | } // namespace __sanitizer |
148 | |