1 //===-- sanitizer_posix_test.cpp ------------------------------------------===// 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 // Tests for POSIX-specific code. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common/sanitizer_platform.h" 14 #if SANITIZER_POSIX 15 16 # include <pthread.h> 17 # include <sys/mman.h> 18 19 # include <algorithm> 20 # include <numeric> 21 22 # include "gtest/gtest.h" 23 # include "sanitizer_common/sanitizer_common.h" 24 25 namespace __sanitizer { 26 27 static pthread_key_t key; 28 static bool destructor_executed; 29 30 extern "C" 31 void destructor(void *arg) { 32 uptr iter = reinterpret_cast<uptr>(arg); 33 if (iter > 1) { 34 ASSERT_EQ(0, pthread_setspecific(key, reinterpret_cast<void *>(iter - 1))); 35 return; 36 } 37 destructor_executed = true; 38 } 39 40 extern "C" 41 void *thread_func(void *arg) { 42 return reinterpret_cast<void*>(pthread_setspecific(key, arg)); 43 } 44 45 static void SpawnThread(uptr iteration) { 46 destructor_executed = false; 47 pthread_t tid; 48 ASSERT_EQ(0, pthread_create(&tid, 0, &thread_func, 49 reinterpret_cast<void *>(iteration))); 50 void *retval; 51 ASSERT_EQ(0, pthread_join(tid, &retval)); 52 ASSERT_EQ(0, retval); 53 } 54 55 TEST(SanitizerCommon, PthreadDestructorIterations) { 56 ASSERT_EQ(0, pthread_key_create(&key, &destructor)); 57 SpawnThread(GetPthreadDestructorIterations()); 58 EXPECT_TRUE(destructor_executed); 59 SpawnThread(GetPthreadDestructorIterations() + 1); 60 #if SANITIZER_SOLARIS 61 // Solaris continues calling destructors beyond PTHREAD_DESTRUCTOR_ITERATIONS. 62 EXPECT_TRUE(destructor_executed); 63 #else 64 EXPECT_FALSE(destructor_executed); 65 #endif 66 ASSERT_EQ(0, pthread_key_delete(key)); 67 } 68 69 TEST(SanitizerCommon, IsAccessibleMemoryRange) { 70 const int page_size = GetPageSize(); 71 InternalMmapVector<char> buffer(3 * page_size); 72 uptr mem = reinterpret_cast<uptr>(buffer.data()); 73 // Protect the middle page. 74 mprotect((void *)(mem + page_size), page_size, PROT_NONE); 75 EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size - 1)); 76 EXPECT_TRUE(IsAccessibleMemoryRange(mem, page_size)); 77 EXPECT_FALSE(IsAccessibleMemoryRange(mem, page_size + 1)); 78 EXPECT_TRUE(IsAccessibleMemoryRange(mem + page_size - 1, 1)); 79 EXPECT_FALSE(IsAccessibleMemoryRange(mem + page_size - 1, 2)); 80 EXPECT_FALSE(IsAccessibleMemoryRange(mem + 2 * page_size - 1, 1)); 81 EXPECT_TRUE(IsAccessibleMemoryRange(mem + 2 * page_size, page_size)); 82 EXPECT_FALSE(IsAccessibleMemoryRange(mem, 3 * page_size)); 83 EXPECT_FALSE(IsAccessibleMemoryRange(0x0, 2)); 84 } 85 86 TEST(SanitizerCommon, IsAccessibleMemoryRangeLarge) { 87 InternalMmapVector<char> buffer(10000 * GetPageSize()); 88 EXPECT_TRUE(IsAccessibleMemoryRange(reinterpret_cast<uptr>(buffer.data()), 89 buffer.size())); 90 } 91 92 TEST(SanitizerCommon, TryMemCpy) { 93 std::vector<char> src(10000000); 94 std::iota(src.begin(), src.end(), 123); 95 std::vector<char> dst; 96 97 // Don't use ::testing::ElementsAreArray or similar, as the huge output on an 98 // error is not helpful. 99 100 dst.assign(1, 0); 101 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 102 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 103 104 dst.assign(100, 0); 105 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 106 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 107 108 dst.assign(534, 0); 109 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 110 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 111 112 dst.assign(GetPageSize(), 0); 113 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 114 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 115 116 dst.assign(src.size(), 0); 117 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 118 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 119 120 dst.assign(src.size() - 1, 0); 121 EXPECT_TRUE(TryMemCpy(dst.data(), src.data(), dst.size())); 122 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), src.begin())); 123 } 124 125 TEST(SanitizerCommon, TryMemCpyNull) { 126 std::vector<char> dst(100); 127 EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size())); 128 } 129 130 TEST(SanitizerCommon, MemCpyAccessible) { 131 const int page_num = 1000; 132 const int page_size = GetPageSize(); 133 InternalMmapVector<char> src(page_num * page_size); 134 std::iota(src.begin(), src.end(), 123); 135 std::vector<char> dst; 136 std::vector<char> exp = {src.begin(), src.end()}; 137 138 // Protect some pages. 139 for (int i = 7; i < page_num; i *= 2) { 140 mprotect(src.data() + i * page_size, page_size, PROT_NONE); 141 std::fill(exp.data() + i * page_size, exp.data() + (i + 1) * page_size, 0); 142 } 143 144 dst.assign(src.size(), 0); 145 EXPECT_FALSE(TryMemCpy(dst.data(), src.data(), dst.size())); 146 147 // Full page aligned range with mprotect pages. 148 dst.assign(src.size(), 0); 149 MemCpyAccessible(dst.data(), src.data(), dst.size()); 150 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin())); 151 152 // Misaligned range with mprotect pages. 153 size_t offb = 3; 154 size_t offe = 7; 155 dst.assign(src.size() - offb - offe, 0); 156 MemCpyAccessible(dst.data(), src.data() + offb, dst.size()); 157 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin() + offb)); 158 159 // Misaligned range with ends in mprotect pages. 160 offb = 3 + 7 * page_size; 161 offe = 7 + 14 * page_size; 162 dst.assign(src.size() - offb - offe, 0); 163 MemCpyAccessible(dst.data(), src.data() + offb, dst.size()); 164 EXPECT_TRUE(std::equal(dst.begin(), dst.end(), exp.begin() + offb)); 165 } 166 167 } // namespace __sanitizer 168 169 #endif // SANITIZER_POSIX 170