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 // libpthread puts the thread descriptor at the end of stack space. 192 void *thread_descriptor_size_test_func(void *arg) { 193 uptr descr_addr = (uptr)pthread_self(); 194 pthread_attr_t attr; 195 pthread_getattr_np(pthread_self(), &attr); 196 void *stackaddr; 197 size_t stacksize; 198 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 199 return (void *)((uptr)stackaddr + stacksize - descr_addr); 200 } 201 202 TEST(SanitizerLinux, ThreadDescriptorSize) { 203 pthread_t tid; 204 void *result; 205 ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0)); 206 ASSERT_EQ(0, pthread_join(tid, &result)); 207 EXPECT_EQ((uptr)result, ThreadDescriptorSize()); 208 } 209 #endif 210 211 TEST(SanitizerCommon, LibraryNameIs) { 212 EXPECT_FALSE(LibraryNameIs("", "")); 213 214 char full_name[256]; 215 const char *paths[] = { "", "/", "/path/to/" }; 216 const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" }; 217 const char *base_names[] = { "lib", "lib.0", "lib-i386" }; 218 const char *wrong_names[] = { "", "lib.9", "lib-x86_64" }; 219 for (uptr i = 0; i < ARRAY_SIZE(paths); i++) 220 for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) { 221 for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) { 222 internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so", 223 paths[i], base_names[k], suffixes[j]); 224 EXPECT_TRUE(LibraryNameIs(full_name, base_names[k])) 225 << "Full name " << full_name 226 << " doesn't match base name " << base_names[k]; 227 for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++) 228 EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m])) 229 << "Full name " << full_name 230 << " matches base name " << wrong_names[m]; 231 } 232 } 233 } 234 235 #if defined(__mips64) 236 // Effectively, this is a test for ThreadDescriptorSize() which is used to 237 // compute ThreadSelf(). 238 TEST(SanitizerLinux, ThreadSelfTest) { 239 ASSERT_EQ(pthread_self(), ThreadSelf()); 240 } 241 #endif 242 243 TEST(SanitizerCommon, StartSubprocessTest) { 244 int pipe_fds[2]; 245 ASSERT_EQ(0, pipe(pipe_fds)); 246 #if SANITIZER_ANDROID 247 const char *shell = "/system/bin/sh"; 248 #else 249 const char *shell = "/bin/sh"; 250 #endif 251 const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; 252 int pid = StartSubprocess(shell, argv, GetEnviron(), 253 /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); 254 ASSERT_GT(pid, 0); 255 256 // wait for process to finish. 257 while (IsProcessRunning(pid)) { 258 } 259 ASSERT_FALSE(IsProcessRunning(pid)); 260 261 char buffer[256]; 262 { 263 char *ptr = buffer; 264 uptr bytes_read; 265 while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) { 266 if (!bytes_read) { 267 break; 268 } 269 ptr += bytes_read; 270 } 271 ASSERT_EQ(5, ptr - buffer); 272 *ptr = 0; 273 } 274 ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer; 275 internal_close(pipe_fds[0]); 276 } 277 278 } // namespace __sanitizer 279 280 #endif // SANITIZER_LINUX 281