170 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Tests for POSIX-specific code.10//11//===----------------------------------------------------------------------===//12 13#include "sanitizer_common/sanitizer_platform.h"14#if SANITIZER_POSIX15 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 25namespace __sanitizer {26 27static pthread_key_t key;28static bool destructor_executed;29 30extern "C"31void 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 40extern "C"41void *thread_func(void *arg) {42 return reinterpret_cast<void*>(pthread_setspecific(key, arg));43}44 45static 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 55TEST(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_SOLARIS61 // Solaris continues calling destructors beyond PTHREAD_DESTRUCTOR_ITERATIONS.62 EXPECT_TRUE(destructor_executed);63#else64 EXPECT_FALSE(destructor_executed);65#endif66 ASSERT_EQ(0, pthread_key_delete(key));67}68 69TEST(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 86TEST(SanitizerCommon, IsAccessibleMemoryRangeLarge) {87 InternalMmapVector<char> buffer(10000 * GetPageSize());88 EXPECT_TRUE(IsAccessibleMemoryRange(reinterpret_cast<uptr>(buffer.data()),89 buffer.size()));90}91 92TEST(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 an98 // 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 125TEST(SanitizerCommon, TryMemCpyNull) {126 std::vector<char> dst(100);127 EXPECT_FALSE(TryMemCpy(dst.data(), nullptr, dst.size()));128}129 130TEST(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 __sanitizer168 169#endif // SANITIZER_POSIX170