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 "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 pid_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 pid_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, pid_t *tid); 84 85 static const uptr kThreadCount = 20; 86 87 std::vector<pthread_t> pthread_ids_; 88 std::vector<pid_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, 110 pid_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 == -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<pid_t> ReadTidsToVector(ThreadLister *thread_lister) { 124 std::vector<pid_t> listed_tids; 125 pid_t tid; 126 while ((tid = thread_lister->GetNextTID()) >= 0) 127 listed_tids.push_back(tid); 128 EXPECT_FALSE(thread_lister->error()); 129 return listed_tids; 130 } 131 132 static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) { 133 std::sort(first.begin(), first.end()); 134 std::sort(second.begin(), second.end()); 135 return std::includes(first.begin(), first.end(), 136 second.begin(), second.end()); 137 } 138 139 static bool HasElement(std::vector<pid_t> vector, pid_t element) { 140 return std::find(vector.begin(), vector.end(), element) != vector.end(); 141 } 142 143 // ThreadLister's output should include the current thread's TID and the TID of 144 // every thread we spawned. 145 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { 146 pid_t self_tid = GetTid(); 147 ThreadLister thread_lister(getpid()); 148 std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); 149 ASSERT_TRUE(HasElement(listed_tids, self_tid)); 150 ASSERT_TRUE(Includes(listed_tids, tids_)); 151 } 152 153 // Calling Reset() should not cause ThreadLister to forget any threads it's 154 // supposed to know about. 155 TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) { 156 ThreadLister thread_lister(getpid()); 157 158 // Run the loop body twice, because Reset() might behave differently if called 159 // on a freshly created object. 160 for (uptr i = 0; i < 2; i++) { 161 thread_lister.Reset(); 162 std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); 163 ASSERT_TRUE(Includes(listed_tids, tids_)); 164 } 165 } 166 167 // If new threads have spawned during ThreadLister object's lifetime, calling 168 // Reset() should cause ThreadLister to recognize their existence. 169 TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) { 170 ThreadLister thread_lister(getpid()); 171 std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister); 172 173 pthread_t extra_pthread_id; 174 pid_t extra_tid; 175 SpawnTidReporter(&extra_pthread_id, &extra_tid); 176 // Register the new thread so it gets terminated in TearDown(). 177 pthread_ids_.push_back(extra_pthread_id); 178 179 // It would be very bizarre if the new TID had been listed before we even 180 // spawned that thread, but it would also cause a false success in this test, 181 // so better check for that. 182 ASSERT_FALSE(HasElement(threads_before_extra, extra_tid)); 183 184 thread_lister.Reset(); 185 186 std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister); 187 ASSERT_TRUE(HasElement(threads_after_extra, extra_tid)); 188 } 189 190 TEST(SanitizerCommon, SetEnvTest) { 191 const char kEnvName[] = "ENV_FOO"; 192 SetEnv(kEnvName, "value"); 193 EXPECT_STREQ("value", getenv(kEnvName)); 194 unsetenv(kEnvName); 195 EXPECT_EQ(0, getenv(kEnvName)); 196 } 197 198 #if defined(__x86_64__) || defined(__i386__) 199 void *thread_self_offset_test_func(void *arg) { 200 bool result = 201 *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf(); 202 return (void *)result; 203 } 204 205 TEST(SanitizerLinux, ThreadSelfOffset) { 206 EXPECT_TRUE((bool)thread_self_offset_test_func(0)); 207 pthread_t tid; 208 void *result; 209 ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0)); 210 ASSERT_EQ(0, pthread_join(tid, &result)); 211 EXPECT_TRUE((bool)result); 212 } 213 214 // libpthread puts the thread descriptor at the end of stack space. 215 void *thread_descriptor_size_test_func(void *arg) { 216 uptr descr_addr = ThreadSelf(); 217 pthread_attr_t attr; 218 pthread_getattr_np(pthread_self(), &attr); 219 void *stackaddr; 220 size_t stacksize; 221 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 222 return (void *)((uptr)stackaddr + stacksize - descr_addr); 223 } 224 225 TEST(SanitizerLinux, ThreadDescriptorSize) { 226 pthread_t tid; 227 void *result; 228 ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0)); 229 ASSERT_EQ(0, pthread_join(tid, &result)); 230 EXPECT_EQ((uptr)result, ThreadDescriptorSize()); 231 } 232 #endif 233 234 TEST(SanitizerCommon, LibraryNameIs) { 235 EXPECT_FALSE(LibraryNameIs("", "")); 236 237 char full_name[256]; 238 const char *paths[] = { "", "/", "/path/to/" }; 239 const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" }; 240 const char *base_names[] = { "lib", "lib.0", "lib-i386" }; 241 const char *wrong_names[] = { "", "lib.9", "lib-x86_64" }; 242 for (uptr i = 0; i < ARRAY_SIZE(paths); i++) 243 for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) { 244 for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) { 245 internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so", 246 paths[i], base_names[k], suffixes[j]); 247 EXPECT_TRUE(LibraryNameIs(full_name, base_names[k])) 248 << "Full name " << full_name 249 << " doesn't match base name " << base_names[k]; 250 for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++) 251 EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m])) 252 << "Full name " << full_name 253 << " matches base name " << wrong_names[m]; 254 } 255 } 256 } 257 258 } // namespace __sanitizer 259 260 #endif // SANITIZER_LINUX 261