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