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