1//===-- sanitizer_atomic_test.cc ------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11//
12//===----------------------------------------------------------------------===//
13#include "sanitizer_common/sanitizer_atomic.h"
14#include "gtest/gtest.h"
15
16namespace __sanitizer {
17
18template<typename T>
19struct ValAndMagic {
20  typename T::Type magic0;
21  T a;
22  typename T::Type magic1;
23
24  static ValAndMagic<T> *sink;
25};
26
27template<typename T>
28ValAndMagic<T> *ValAndMagic<T>::sink;
29
30template<typename T, memory_order load_mo, memory_order store_mo>
31void CheckStoreLoad() {
32  typedef typename T::Type Type;
33  ValAndMagic<T> val;
34  // Prevent the compiler from scalarizing the struct.
35  ValAndMagic<T>::sink = &val;
36  // Ensure that surrounding memory is not overwritten.
37  val.magic0 = val.magic1 = (Type)-3;
38  for (u64 i = 0; i < 100; i++) {
39    // Generate a value that occupies all bytes of the variable.
40    u64 v = i;
41    v |= v << 8;
42    v |= v << 16;
43    v |= v << 32;
44    val.a.val_dont_use = (Type)v;
45    EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
46    val.a.val_dont_use = (Type)-1;
47    atomic_store(&val.a, (Type)v, store_mo);
48    EXPECT_EQ(val.a.val_dont_use, (Type)v);
49  }
50  EXPECT_EQ(val.magic0, (Type)-3);
51  EXPECT_EQ(val.magic1, (Type)-3);
52}
53
54TEST(SanitizerCommon, AtomicStoreLoad) {
55  CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
56  CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
57  CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
58  CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
59  CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
60
61  CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
62  CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
63  CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
64  CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
65  CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
66
67  CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
68  CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
69  CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
70  CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
71  CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
72
73  CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
74  CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
75  CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
76  CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
77  CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
78
79  CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
80      ();
81  CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
82      ();
83  CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
84      ();
85  CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
86      ();
87  CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
88      ();
89}
90
91// Clang crashes while compiling this test for Android:
92// http://llvm.org/bugs/show_bug.cgi?id=15587
93#if !SANITIZER_ANDROID
94template<typename T>
95void CheckAtomicCompareExchange() {
96  typedef typename T::Type Type;
97  {
98    Type old_val = 42;
99    Type new_val = 24;
100    Type var = old_val;
101    EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
102                                               memory_order_relaxed));
103    EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
104                                                memory_order_relaxed));
105    EXPECT_EQ(new_val, old_val);
106  }
107  {
108    Type old_val = 42;
109    Type new_val = 24;
110    Type var = old_val;
111    EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
112                                             memory_order_relaxed));
113    EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
114                                              memory_order_relaxed));
115    EXPECT_EQ(new_val, old_val);
116  }
117}
118
119TEST(SanitizerCommon, AtomicCompareExchangeTest) {
120  CheckAtomicCompareExchange<atomic_uint8_t>();
121  CheckAtomicCompareExchange<atomic_uint16_t>();
122  CheckAtomicCompareExchange<atomic_uint32_t>();
123  CheckAtomicCompareExchange<atomic_uint64_t>();
124  CheckAtomicCompareExchange<atomic_uintptr_t>();
125}
126#endif  //!SANITIZER_ANDROID
127
128}  // namespace __sanitizer
129