1 //===-- atomic_test.cpp -----------------------------------------*- C++ -*-===//
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 #include "scudo/standalone/atomic_helpers.h"
10 #include "gtest/gtest.h"
11 
12 namespace scudo {
13 
14 template <typename T> struct ValAndMagic {
15   typename T::Type Magic0;
16   T A;
17   typename T::Type Magic1;
18 
19   static ValAndMagic<T> *Sink;
20 };
21 
22 template <typename T> ValAndMagic<T> *ValAndMagic<T>::Sink;
23 
24 template <typename T, memory_order LoadMO, memory_order StoreMO>
25 void checkStoreLoad() {
26   typedef typename T::Type Type;
27   ValAndMagic<T> Val;
28   // Prevent the compiler from scalarizing the struct.
29   ValAndMagic<T>::Sink = &Val;
30   // Ensure that surrounding memory is not overwritten.
31   Val.Magic0 = Val.Magic1 = (Type)-3;
32   for (u64 I = 0; I < 100; I++) {
33     // Generate A value that occupies all bytes of the variable.
34     u64 V = I;
35     V |= V << 8;
36     V |= V << 16;
37     V |= V << 32;
38     Val.A.ValDoNotUse = (Type)V;
39     EXPECT_EQ(atomic_load(&Val.A, LoadMO), (Type)V);
40     Val.A.ValDoNotUse = (Type)-1;
41     atomic_store(&Val.A, (Type)V, StoreMO);
42     EXPECT_EQ(Val.A.ValDoNotUse, (Type)V);
43   }
44   EXPECT_EQ(Val.Magic0, (Type)-3);
45   EXPECT_EQ(Val.Magic1, (Type)-3);
46 }
47 
48 TEST(ScudoAtomicTest, AtomicStoreLoad) {
49   checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_relaxed>();
50   checkStoreLoad<atomic_u8, memory_order_consume, memory_order_relaxed>();
51   checkStoreLoad<atomic_u8, memory_order_acquire, memory_order_relaxed>();
52   checkStoreLoad<atomic_u8, memory_order_relaxed, memory_order_release>();
53   checkStoreLoad<atomic_u8, memory_order_seq_cst, memory_order_seq_cst>();
54 
55   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_relaxed>();
56   checkStoreLoad<atomic_u16, memory_order_consume, memory_order_relaxed>();
57   checkStoreLoad<atomic_u16, memory_order_acquire, memory_order_relaxed>();
58   checkStoreLoad<atomic_u16, memory_order_relaxed, memory_order_release>();
59   checkStoreLoad<atomic_u16, memory_order_seq_cst, memory_order_seq_cst>();
60 
61   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_relaxed>();
62   checkStoreLoad<atomic_u32, memory_order_consume, memory_order_relaxed>();
63   checkStoreLoad<atomic_u32, memory_order_acquire, memory_order_relaxed>();
64   checkStoreLoad<atomic_u32, memory_order_relaxed, memory_order_release>();
65   checkStoreLoad<atomic_u32, memory_order_seq_cst, memory_order_seq_cst>();
66 
67   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_relaxed>();
68   checkStoreLoad<atomic_u64, memory_order_consume, memory_order_relaxed>();
69   checkStoreLoad<atomic_u64, memory_order_acquire, memory_order_relaxed>();
70   checkStoreLoad<atomic_u64, memory_order_relaxed, memory_order_release>();
71   checkStoreLoad<atomic_u64, memory_order_seq_cst, memory_order_seq_cst>();
72 
73   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_relaxed>();
74   checkStoreLoad<atomic_uptr, memory_order_consume, memory_order_relaxed>();
75   checkStoreLoad<atomic_uptr, memory_order_acquire, memory_order_relaxed>();
76   checkStoreLoad<atomic_uptr, memory_order_relaxed, memory_order_release>();
77   checkStoreLoad<atomic_uptr, memory_order_seq_cst, memory_order_seq_cst>();
78 }
79 
80 template <typename T> void checkAtomicCompareExchange() {
81   typedef typename T::Type Type;
82   {
83     Type OldVal = 42;
84     Type NewVal = 24;
85     Type V = OldVal;
86     EXPECT_TRUE(atomic_compare_exchange_strong(
87         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
88     EXPECT_FALSE(atomic_compare_exchange_strong(
89         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
90     EXPECT_EQ(NewVal, OldVal);
91   }
92   {
93     Type OldVal = 42;
94     Type NewVal = 24;
95     Type V = OldVal;
96     EXPECT_TRUE(atomic_compare_exchange_weak(reinterpret_cast<T *>(&V), &OldVal,
97                                              NewVal, memory_order_relaxed));
98     EXPECT_FALSE(atomic_compare_exchange_weak(
99         reinterpret_cast<T *>(&V), &OldVal, NewVal, memory_order_relaxed));
100     EXPECT_EQ(NewVal, OldVal);
101   }
102 }
103 
104 TEST(ScudoAtomicTest, AtomicCompareExchangeTest) {
105   checkAtomicCompareExchange<atomic_u8>();
106   checkAtomicCompareExchange<atomic_u16>();
107   checkAtomicCompareExchange<atomic_u32>();
108   checkAtomicCompareExchange<atomic_u64>();
109   checkAtomicCompareExchange<atomic_uptr>();
110 }
111 
112 } // namespace scudo
113