1 //===-- sanitizer_posix_test.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Tests for POSIX-specific code.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
17 # include <sys/mman.h>
22 # include "gtest/gtest.h"
23 # include "sanitizer_common/sanitizer_common.h"
25 namespace __sanitizer
{
27 static pthread_key_t key
;
28 static bool destructor_executed
;
31 void destructor(void *arg
) {
32 uptr iter
= reinterpret_cast<uptr
>(arg
);
34 ASSERT_EQ(0, pthread_setspecific(key
, reinterpret_cast<void *>(iter
- 1)));
37 destructor_executed
= true;
41 void *thread_func(void *arg
) {
42 return reinterpret_cast<void*>(pthread_setspecific(key
, arg
));
45 static void SpawnThread(uptr iteration
) {
46 destructor_executed
= false;
48 ASSERT_EQ(0, pthread_create(&tid
, 0, &thread_func
,
49 reinterpret_cast<void *>(iteration
)));
51 ASSERT_EQ(0, pthread_join(tid
, &retval
));
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);
61 // Solaris continues calling destructors beyond PTHREAD_DESTRUCTOR_ITERATIONS.
62 EXPECT_TRUE(destructor_executed
);
64 EXPECT_FALSE(destructor_executed
);
66 ASSERT_EQ(0, pthread_key_delete(key
));
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));
86 TEST(SanitizerCommon
, IsAccessibleMemoryRangeLarge
) {
87 InternalMmapVector
<char> buffer(10000 * GetPageSize());
88 EXPECT_TRUE(IsAccessibleMemoryRange(reinterpret_cast<uptr
>(buffer
.data()),
92 TEST(SanitizerCommon
, TryMemCpy
) {
93 std::vector
<char> src(10000000);
94 std::iota(src
.begin(), src
.end(), 123);
95 std::vector
<char> dst
;
97 // Don't use ::testing::ElementsAreArray or similar, as the huge output on an
98 // error is not helpful.
101 EXPECT_TRUE(TryMemCpy(dst
.data(), src
.data(), dst
.size()));
102 EXPECT_TRUE(std::equal(dst
.begin(), dst
.end(), src
.begin()));
105 EXPECT_TRUE(TryMemCpy(dst
.data(), src
.data(), dst
.size()));
106 EXPECT_TRUE(std::equal(dst
.begin(), dst
.end(), src
.begin()));
109 EXPECT_TRUE(TryMemCpy(dst
.data(), src
.data(), dst
.size()));
110 EXPECT_TRUE(std::equal(dst
.begin(), dst
.end(), src
.begin()));
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()));
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()));
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()));
125 TEST(SanitizerCommon
, TryMemCpyNull
) {
126 std::vector
<char> dst(100);
127 EXPECT_FALSE(TryMemCpy(dst
.data(), nullptr, dst
.size()));
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()};
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);
144 dst
.assign(src
.size(), 0);
145 EXPECT_FALSE(TryMemCpy(dst
.data(), src
.data(), dst
.size()));
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()));
152 // Misaligned range with mprotect pages.
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
));
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
));
167 } // namespace __sanitizer
169 #endif // SANITIZER_POSIX