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
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: key, pointer: 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: key, pointer: arg));
43}
44
45static void SpawnThread(uptr iteration) {
46 destructor_executed = false;
47 pthread_t tid;
48 ASSERT_EQ(0, pthread_create(newthread: &tid, attr: 0, start_routine: &thread_func,
49 arg: reinterpret_cast<void *>(iteration)));
50 void *retval;
51 ASSERT_EQ(0, pthread_join(th: tid, thread_return: &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_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
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 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
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 __sanitizer
168
169#endif // SANITIZER_POSIX
170

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp