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