1 //===----------------------------------------------------------------------===// 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 // UNSUPPORTED: c++03 10 11 #define TESTING_CXA_GUARD 12 #include "../src/cxa_guard_impl.h" 13 #include <cassert> 14 15 // Disable GCC warning about tautological comparison of a function's address 16 #if defined(__GNUC__) && !defined(__clang__) 17 # pragma GCC diagnostic ignored "-Waddress" 18 #endif 19 20 using namespace __cxxabiv1; 21 22 template <class GuardType, class Impl> 23 struct Tests { 24 private: 25 Tests() : g{}, impl(&g) {} 26 GuardType g; 27 Impl impl; 28 29 uint8_t first_byte() { 30 uint8_t first; 31 std::memcpy(&first, &g, 1); 32 return first; 33 } 34 35 void reset() { g = {}; } 36 37 public: 38 // Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and 39 // cxa_guard_release. Specifically, that they leave the first byte with 40 // the value 0 or 1 as specified by the ARM or Itanium specification. 41 static void test() { 42 Tests tests; 43 tests.test_acquire(); 44 tests.test_abort(); 45 tests.test_release(); 46 } 47 48 void test_acquire() { 49 { 50 reset(); 51 assert(first_byte() == 0); 52 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING); 53 assert(first_byte() == 0); 54 } 55 { 56 reset(); 57 assert(first_byte() == 0); 58 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING); 59 impl.cxa_guard_release(); 60 assert(first_byte() == 1); 61 assert(impl.cxa_guard_acquire() == INIT_IS_DONE); 62 } 63 } 64 65 void test_release() { 66 { 67 reset(); 68 assert(first_byte() == 0); 69 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING); 70 assert(first_byte() == 0); 71 impl.cxa_guard_release(); 72 assert(first_byte() == 1); 73 } 74 } 75 76 void test_abort() { 77 { 78 reset(); 79 assert(first_byte() == 0); 80 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING); 81 assert(first_byte() == 0); 82 impl.cxa_guard_abort(); 83 assert(first_byte() == 0); 84 assert(impl.cxa_guard_acquire() == INIT_IS_PENDING); 85 assert(first_byte() == 0); 86 } 87 } 88 }; 89 90 struct NopMutex { 91 bool lock() { 92 assert(!is_locked); 93 is_locked = true; 94 return false; 95 } 96 bool unlock() { 97 assert(is_locked); 98 is_locked = false; 99 return false; 100 } 101 102 private: 103 bool is_locked = false; 104 }; 105 NopMutex global_nop_mutex = {}; 106 107 struct NopCondVar { 108 bool broadcast() { return false; } 109 bool wait(NopMutex&) { return false; } 110 }; 111 NopCondVar global_nop_cond = {}; 112 113 void NopFutexWait(int*, int) { assert(false); } 114 void NopFutexWake(int*) { assert(false); } 115 uint32_t MockGetThreadID() { return 0; } 116 117 int main(int, char**) { 118 { 119 #if defined(_LIBCXXABI_HAS_NO_THREADS) 120 static_assert(CurrentImplementation == Implementation::NoThreads, ""); 121 static_assert( 122 std::is_same<SelectedImplementation, InitByteNoThreads>::value, ""); 123 #else 124 static_assert(CurrentImplementation == Implementation::GlobalMutex, ""); 125 static_assert( 126 std::is_same< 127 SelectedImplementation, 128 InitByteGlobalMutex<LibcppMutex, LibcppCondVar, 129 GlobalStatic<LibcppMutex>::instance, 130 GlobalStatic<LibcppCondVar>::instance>>::value, 131 ""); 132 #endif 133 } 134 { 135 #if (defined(__APPLE__) || defined(__linux__)) && !defined(_LIBCXXABI_HAS_NO_THREADS) 136 assert(PlatformThreadID); 137 #endif 138 if (PlatformSupportsThreadID()) { 139 assert(PlatformThreadID() != 0); 140 assert(PlatformThreadID() == PlatformThreadID()); 141 } 142 } 143 { 144 Tests<uint32_t, InitByteNoThreads>::test(); 145 Tests<uint64_t, InitByteNoThreads>::test(); 146 } 147 { 148 using MutexImpl = 149 InitByteGlobalMutex<NopMutex, NopCondVar, global_nop_mutex, 150 global_nop_cond, MockGetThreadID>; 151 Tests<uint32_t, MutexImpl>::test(); 152 Tests<uint64_t, MutexImpl>::test(); 153 } 154 { 155 using FutexImpl = 156 InitByteFutex<&NopFutexWait, &NopFutexWake, &MockGetThreadID>; 157 Tests<uint32_t, FutexImpl>::test(); 158 Tests<uint64_t, FutexImpl>::test(); 159 } 160 161 return 0; 162 } 163