1 //===-- sanitizer_linux_test.cc -------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // Tests for sanitizer_linux.h 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "sanitizer_common/sanitizer_platform.h" 15 #if SANITIZER_LINUX 16 17 #include "sanitizer_common/sanitizer_linux.h" 18 19 #include "sanitizer_common/sanitizer_common.h" 20 #include "sanitizer_common/sanitizer_file.h" 21 #include "gtest/gtest.h" 22 23 #include <pthread.h> 24 #include <sched.h> 25 #include <stdlib.h> 26 27 #include <algorithm> 28 #include <vector> 29 30 namespace __sanitizer { 31 32 struct TidReporterArgument { 33 TidReporterArgument() { 34 pthread_mutex_init(&terminate_thread_mutex, NULL); 35 pthread_mutex_init(&tid_reported_mutex, NULL); 36 pthread_cond_init(&terminate_thread_cond, NULL); 37 pthread_cond_init(&tid_reported_cond, NULL); 38 terminate_thread = false; 39 } 40 41 ~TidReporterArgument() { 42 pthread_mutex_destroy(&terminate_thread_mutex); 43 pthread_mutex_destroy(&tid_reported_mutex); 44 pthread_cond_destroy(&terminate_thread_cond); 45 pthread_cond_destroy(&tid_reported_cond); 46 } 47 48 tid_t reported_tid; 49 // For signaling to spawned threads that they should terminate. 50 pthread_cond_t terminate_thread_cond; 51 pthread_mutex_t terminate_thread_mutex; 52 bool terminate_thread; 53 // For signaling to main thread that a child thread has reported its tid. 54 pthread_cond_t tid_reported_cond; 55 pthread_mutex_t tid_reported_mutex; 56 57 private: 58 // Disallow evil constructors 59 TidReporterArgument(const TidReporterArgument &); 60 void operator=(const TidReporterArgument &); 61 }; 62 63 class ThreadListerTest : public ::testing::Test { 64 protected: 65 virtual void SetUp() { 66 pthread_t pthread_id; 67 tid_t tid; 68 for (uptr i = 0; i < kThreadCount; i++) { 69 SpawnTidReporter(&pthread_id, &tid); 70 pthread_ids_.push_back(pthread_id); 71 tids_.push_back(tid); 72 } 73 } 74 75 virtual void TearDown() { 76 pthread_mutex_lock(&thread_arg.terminate_thread_mutex); 77 thread_arg.terminate_thread = true; 78 pthread_cond_broadcast(&thread_arg.terminate_thread_cond); 79 pthread_mutex_unlock(&thread_arg.terminate_thread_mutex); 80 for (uptr i = 0; i < pthread_ids_.size(); i++) 81 pthread_join(pthread_ids_[i], NULL); 82 } 83 84 void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid); 85 86 static const uptr kThreadCount = 20; 87 88 std::vector<pthread_t> pthread_ids_; 89 std::vector<tid_t> tids_; 90 91 TidReporterArgument thread_arg; 92 }; 93 94 // Writes its TID once to reported_tid and waits until signaled to terminate. 95 void *TidReporterThread(void *argument) { 96 TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument); 97 pthread_mutex_lock(&arg->tid_reported_mutex); 98 arg->reported_tid = GetTid(); 99 pthread_cond_broadcast(&arg->tid_reported_cond); 100 pthread_mutex_unlock(&arg->tid_reported_mutex); 101 102 pthread_mutex_lock(&arg->terminate_thread_mutex); 103 while (!arg->terminate_thread) 104 pthread_cond_wait(&arg->terminate_thread_cond, 105 &arg->terminate_thread_mutex); 106 pthread_mutex_unlock(&arg->terminate_thread_mutex); 107 return NULL; 108 } 109 110 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) { 111 pthread_mutex_lock(&thread_arg.tid_reported_mutex); 112 thread_arg.reported_tid = -1; 113 ASSERT_EQ(0, pthread_create(pthread_id, NULL, 114 TidReporterThread, 115 &thread_arg)); 116 while (thread_arg.reported_tid == (tid_t)(-1)) 117 pthread_cond_wait(&thread_arg.tid_reported_cond, 118 &thread_arg.tid_reported_mutex); 119 pthread_mutex_unlock(&thread_arg.tid_reported_mutex); 120 *tid = thread_arg.reported_tid; 121 } 122 123 static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) { 124 std::vector<tid_t> listed_tids; 125 InternalMmapVector<tid_t> threads(128); 126 EXPECT_TRUE(thread_lister->ListThreads(&threads)); 127 return std::vector<tid_t>(threads.begin(), threads.end()); 128 } 129 130 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) { 131 std::sort(first.begin(), first.end()); 132 std::sort(second.begin(), second.end()); 133 return std::includes(first.begin(), first.end(), 134 second.begin(), second.end()); 135 } 136 137 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) { 138 return std::find(vector.begin(), vector.end(), element) != vector.end(); 139 } 140 141 // ThreadLister's output should include the current thread's TID and the TID of 142 // every thread we spawned. 143 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { 144 tid_t self_tid = GetTid(); 145 ThreadLister thread_lister(getpid()); 146 std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister); 147 ASSERT_TRUE(HasElement(listed_tids, self_tid)); 148 ASSERT_TRUE(Includes(listed_tids, tids_)); 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 void *thread_self_offset_test_func(void *arg) { 193 bool result = 194 *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf(); 195 return (void *)result; 196 } 197 198 TEST(SanitizerLinux, ThreadSelfOffset) { 199 EXPECT_TRUE((bool)thread_self_offset_test_func(0)); 200 pthread_t tid; 201 void *result; 202 ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0)); 203 ASSERT_EQ(0, pthread_join(tid, &result)); 204 EXPECT_TRUE((bool)result); 205 } 206 207 // libpthread puts the thread descriptor at the end of stack space. 208 void *thread_descriptor_size_test_func(void *arg) { 209 uptr descr_addr = ThreadSelf(); 210 pthread_attr_t attr; 211 pthread_getattr_np(pthread_self(), &attr); 212 void *stackaddr; 213 size_t stacksize; 214 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 215 return (void *)((uptr)stackaddr + stacksize - descr_addr); 216 } 217 218 TEST(SanitizerLinux, ThreadDescriptorSize) { 219 pthread_t tid; 220 void *result; 221 ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0)); 222 ASSERT_EQ(0, pthread_join(tid, &result)); 223 EXPECT_EQ((uptr)result, ThreadDescriptorSize()); 224 } 225 #endif 226 227 TEST(SanitizerCommon, LibraryNameIs) { 228 EXPECT_FALSE(LibraryNameIs("", "")); 229 230 char full_name[256]; 231 const char *paths[] = { "", "/", "/path/to/" }; 232 const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" }; 233 const char *base_names[] = { "lib", "lib.0", "lib-i386" }; 234 const char *wrong_names[] = { "", "lib.9", "lib-x86_64" }; 235 for (uptr i = 0; i < ARRAY_SIZE(paths); i++) 236 for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) { 237 for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) { 238 internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so", 239 paths[i], base_names[k], suffixes[j]); 240 EXPECT_TRUE(LibraryNameIs(full_name, base_names[k])) 241 << "Full name " << full_name 242 << " doesn't match base name " << base_names[k]; 243 for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++) 244 EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m])) 245 << "Full name " << full_name 246 << " matches base name " << wrong_names[m]; 247 } 248 } 249 } 250 251 #if defined(__mips64) 252 // Effectively, this is a test for ThreadDescriptorSize() which is used to 253 // compute ThreadSelf(). 254 TEST(SanitizerLinux, ThreadSelfTest) { 255 ASSERT_EQ(pthread_self(), ThreadSelf()); 256 } 257 #endif 258 259 TEST(SanitizerCommon, StartSubprocessTest) { 260 int pipe_fds[2]; 261 ASSERT_EQ(0, pipe(pipe_fds)); 262 #if SANITIZER_ANDROID 263 const char *shell = "/system/bin/sh"; 264 #else 265 const char *shell = "/bin/sh"; 266 #endif 267 const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL}; 268 int pid = StartSubprocess(shell, argv, 269 /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]); 270 ASSERT_GT(pid, 0); 271 272 // wait for process to finish. 273 while (IsProcessRunning(pid)) { 274 } 275 ASSERT_FALSE(IsProcessRunning(pid)); 276 277 char buffer[256]; 278 { 279 char *ptr = buffer; 280 uptr bytes_read; 281 while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) { 282 if (!bytes_read) { 283 break; 284 } 285 ptr += bytes_read; 286 } 287 ASSERT_EQ(5, ptr - buffer); 288 *ptr = 0; 289 } 290 ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer; 291 internal_close(pipe_fds[0]); 292 } 293 294 } // namespace __sanitizer 295 296 #endif // SANITIZER_LINUX 297