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