xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_posix_test.cpp (revision 7106de9573c29db5d107a2f4ab02d8621eea2510)
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