xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_atomic_test.cpp (revision 029005a2e20fe65f850bd000d0d71008eff669ed)
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>
CheckStoreLoad()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 
TEST(SanitizerCommon,AtomicStoreLoad)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>
CheckAtomicCompareExchange()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 
TEST(SanitizerCommon,AtomicCompareExchangeTest)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