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