1 //===-- sanitizer_linux_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 sanitizer_linux.h 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "sanitizer_common/sanitizer_platform.h" 14 #if SANITIZER_LINUX 15 16 #include "sanitizer_common/sanitizer_linux.h" 17 18 #include "sanitizer_common/sanitizer_common.h" 19 #include "sanitizer_common/sanitizer_file.h" 20 #include "gtest/gtest.h" 21 22 #include <pthread.h> 23 #include <sched.h> 24 #include <stdlib.h> 25 26 #include <algorithm> 27 #include <vector> 28 29 namespace __sanitizer { 30 31 struct TidReporterArgument { 32 TidReporterArgument() { 33 pthread_mutex_init(&terminate_thread_mutex, NULL); 34 pthread_mutex_init(&tid_reported_mutex, NULL); 35 pthread_cond_init(&terminate_thread_cond, NULL); 36 pthread_cond_init(&tid_reported_cond, NULL); 37 terminate_thread = false; 38 } 39 40 ~TidReporterArgument() { 41 pthread_mutex_destroy(&terminate_thread_mutex); 42 pthread_mutex_destroy(&tid_reported_mutex); 43 pthread_cond_destroy(&terminate_thread_cond); 44 pthread_cond_destroy(&tid_reported_cond); 45 } 46 47 tid_t reported_tid; 48 // For signaling to spawned threads that they should terminate. 49 pthread_cond_t terminate_thread_cond; 50 pthread_mutex_t terminate_thread_mutex; 51 bool terminate_thread; 52 // For signaling to main thread that a child thread has reported its tid. 53 pthread_cond_t tid_reported_cond; 54 pthread_mutex_t tid_reported_mutex; 55 56 private: 57 // Disallow evil constructors 58 TidReporterArgument(const TidReporterArgument &); 59 void operator=(const TidReporterArgument &); 60 }; 61 62 class ThreadListerTest : public ::testing::Test { 63 protected: 64 virtual void SetUp() { 65 pthread_t pthread_id; 66 tid_t tid; 67 for (uptr i = 0; i < kThreadCount; i++) { 68 SpawnTidReporter(&pthread_id, &tid); 69 pthread_ids_.push_back(pthread_id); 70 tids_.push_back(tid); 71 } 72 } 73 74 virtual void TearDown() { 75 pthread_mutex_lock(&thread_arg.terminate_thread_mutex); 76 thread_arg.terminate_thread = true; 77 pthread_cond_broadcast(&thread_arg.terminate_thread_cond); 78 pthread_mutex_unlock(&thread_arg.terminate_thread_mutex); 79 for (uptr i = 0; i < pthread_ids_.size(); i++) 80 pthread_join(pthread_ids_[i], NULL); 81 } 82 83 void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid); 84 85 static const uptr kThreadCount = 20; 86 87 std::vector<pthread_t> pthread_ids_; 88 std::vector<tid_t> tids_; 89 90 TidReporterArgument thread_arg; 91 }; 92 93 // Writes its TID once to reported_tid and waits until signaled to terminate. 94 void *TidReporterThread(void *argument) { 95 TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument); 96 pthread_mutex_lock(&arg->tid_reported_mutex); 97 arg->reported_tid = GetTid(); 98 pthread_cond_broadcast(&arg->tid_reported_cond); 99 pthread_mutex_unlock(&arg->tid_reported_mutex); 100 101 pthread_mutex_lock(&arg->terminate_thread_mutex); 102 while (!arg->terminate_thread) 103 pthread_cond_wait(&arg->terminate_thread_cond, 104 &arg->terminate_thread_mutex); 105 pthread_mutex_unlock(&arg->terminate_thread_mutex); 106 return NULL; 107 } 108 109 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) { 110 pthread_mutex_lock(&thread_arg.tid_reported_mutex); 111 thread_arg.reported_tid = -1; 112 ASSERT_EQ(0, pthread_create(pthread_id, NULL, 113 TidReporterThread, 114 &thread_arg)); 115 while (thread_arg.reported_tid == (tid_t)(-1)) 116 pthread_cond_wait(&thread_arg.tid_reported_cond, 117 &thread_arg.tid_reported_mutex); 118 pthread_mutex_unlock(&thread_arg.tid_reported_mutex); 119 *tid = thread_arg.reported_tid; 120 } 121 122 static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) { 123 std::vector<tid_t> listed_tids; 124 InternalMmapVector<tid_t> threads(128); 125 EXPECT_TRUE(thread_lister->ListThreads(&threads)); 126 return std::vector<tid_t>(threads.begin(), threads.end()); 127 } 128 129 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) { 130 std::sort(first.begin(), first.end()); 131 std::sort(second.begin(), second.end()); 132 return std::includes(first.begin(), first.end(), 133 second.begin(), second.end()); 134 } 135 136 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) { 137 return std::find(vector.begin(), vector.end(), element) != vector.end(); 138 } 139 140 // ThreadLister's output should include the current thread's TID and the TID of 141 // every thread we spawned. 142 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { 143 tid_t self_tid = GetTid(); 144 ThreadLister thread_lister(getpid()); 145 std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister); 146 ASSERT_TRUE(HasElement(listed_tids, self_tid)); 147 ASSERT_TRUE(Includes(listed_tids, tids_)); 148 } 149 150 TEST_F(ThreadListerTest, DoNotForgetThreads) { 151 ThreadLister thread_lister(getpid()); 152 153 // Run the loop body twice, because ThreadLister might behave differently if 154 // called on a freshly created object. 155 for (uptr i = 0; i < 2; i++) { 156 std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister); 157 ASSERT_TRUE(Includes(listed_tids, tids_)); 158 } 159 } 160 161 // If new threads have spawned during ThreadLister object's lifetime, calling 162 // relisting should cause ThreadLister to recognize their existence. 163 TEST_F(ThreadListerTest, NewThreads) { 164 ThreadLister thread_lister(getpid()); 165 std::vector<tid_t> threads_before_extra = ReadTidsToVector(&thread_lister); 166 167 pthread_t extra_pthread_id; 168 tid_t extra_tid; 169 SpawnTidReporter(&extra_pthread_id, &extra_tid); 170 // Register the new thread so it gets terminated in TearDown(). 171 pthread_ids_.push_back(extra_pthread_id); 172 173 // It would be very bizarre if the new TID had been listed before we even 174 // spawned that thread, but it would also cause a false success in this test, 175 // so better check for that. 176 ASSERT_FALSE(HasElement(threads_before_extra, extra_tid)); 177 178 std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister); 179 ASSERT_TRUE(HasElement(threads_after_extra, extra_tid)); 180 } 181 182 TEST(SanitizerCommon, SetEnvTest) { 183 const char kEnvName[] = "ENV_FOO"; 184 SetEnv(kEnvName, "value"); 185 EXPECT_STREQ("value", getenv(kEnvName)); 186 unsetenv(kEnvName); 187 EXPECT_EQ(0, getenv(kEnvName)); 188 } 189 190 #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID 191 void *thread_self_offset_test_func(void *arg) { 192 bool result = 193 *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf(); 194 return (void *)result; 195 } 196 197 TEST(SanitizerLinux, ThreadSelfOffset) { 198 EXPECT_TRUE((bool)thread_self_offset_test_func(0)); 199 pthread_t tid; 200 void *result; 201 ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0)); 202 ASSERT_EQ(0, pthread_join(tid, &result)); 203 EXPECT_TRUE((bool)result); 204 } 205 206 // libpthread puts the thread descriptor at the end of stack space. 207 void *thread_descriptor_size_test_func(void *arg) { 208 uptr descr_addr = ThreadSelf(); 209 pthread_attr_t attr; 210 pthread_getattr_np(pthread_self(), &attr); 211 void *stackaddr; 212 size_t stacksize; 213 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 214 return (void *)((uptr)stackaddr + stacksize - descr_addr); 215 } 216 217 TEST(SanitizerLinux, ThreadDescriptorSize) { 218 pthread_t tid; 219 void *result; 220 ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0)); 221 ASSERT_EQ(0, pthread_join(tid, &result)); 222 EXPECT_EQ((uptr)result, ThreadDescriptorSize()); 223 } 224 #endif 225 226 TEST(SanitizerCommon, LibraryNameIs) { 227 EXPECT_FALSE(LibraryNameIs("", "")); 228 229 char full_name[256]; 230 const char *paths[] = { "", "/", "/path/to/" }; 231 const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" }; 232 const char *base_names[] = { "lib", "lib.0", "lib-i386" }; 233 const char *wrong_names[] = { "", "lib.9", "lib-x86_64" }; 234 for (uptr i = 0; i < ARRAY_SIZE(paths); i++) 235 for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) { 236 for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) { 237 internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so", 238 paths[i], base_names[k], suffixes[j]); 239 EXPECT_TRUE(LibraryNameIs(full_name, base_names[k])) 240 << "Full name " << full_name 241 << " doesn't match base name " << base_names[k]; 242 for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++) 243 EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m])) 244 << "Full name " << full_name 245 << " matches base name " << wrong_names[m]; 246 } 247 } 248 } 249 250 #if defined(__mips64) 251 // Effectively, this is a test for ThreadDescriptorSize() which is used to 252 // compute ThreadSelf(). 253 TEST(SanitizerLinux, ThreadSelfTest) { 254 ASSERT_EQ(pthread_self(), ThreadSelf()); 255 } 256 #endif 257 258 TEST(SanitizerCommon, StartSubprocessTest) { 259 int pipe_fds[2]; 260 ASSERT_EQ(0, pipe(pipe_fds)); 261 #if SANITIZER_ANDROID 262 const char *shell = "/system/bin/sh"; 263 #else 264 const char *shell = "/bin/sh"; 265 #endif 266 const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; 267 int pid = StartSubprocess(shell, argv, GetEnviron(), 268 /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); 269 ASSERT_GT(pid, 0); 270 271 // wait for process to finish. 272 while (IsProcessRunning(pid)) { 273 } 274 ASSERT_FALSE(IsProcessRunning(pid)); 275 276 char buffer[256]; 277 { 278 char *ptr = buffer; 279 uptr bytes_read; 280 while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) { 281 if (!bytes_read) { 282 break; 283 } 284 ptr += bytes_read; 285 } 286 ASSERT_EQ(5, ptr - buffer); 287 *ptr = 0; 288 } 289 ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer; 290 internal_close(pipe_fds[0]); 291 } 292 293 } // namespace __sanitizer 294 295 #endif // SANITIZER_LINUX 296