sanitizer_linux_test.cc revision f931da85ce8668751628ded926ecad013c5d6f1a
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#ifdef __x86_64__ 23#include <asm/prctl.h> 24#endif 25#include <pthread.h> 26#include <sched.h> 27#include <stdlib.h> 28 29#include <algorithm> 30#include <vector> 31 32#ifdef __x86_64__ 33extern "C" int arch_prctl(int code, __sanitizer::uptr *addr); 34#endif 35 36namespace __sanitizer { 37 38struct TidReporterArgument { 39 TidReporterArgument() { 40 pthread_mutex_init(&terminate_thread_mutex, NULL); 41 pthread_mutex_init(&tid_reported_mutex, NULL); 42 pthread_cond_init(&terminate_thread_cond, NULL); 43 pthread_cond_init(&tid_reported_cond, NULL); 44 terminate_thread = false; 45 } 46 47 ~TidReporterArgument() { 48 pthread_mutex_destroy(&terminate_thread_mutex); 49 pthread_mutex_destroy(&tid_reported_mutex); 50 pthread_cond_destroy(&terminate_thread_cond); 51 pthread_cond_destroy(&tid_reported_cond); 52 } 53 54 pid_t reported_tid; 55 // For signaling to spawned threads that they should terminate. 56 pthread_cond_t terminate_thread_cond; 57 pthread_mutex_t terminate_thread_mutex; 58 bool terminate_thread; 59 // For signaling to main thread that a child thread has reported its tid. 60 pthread_cond_t tid_reported_cond; 61 pthread_mutex_t tid_reported_mutex; 62 63 private: 64 // Disallow evil constructors 65 TidReporterArgument(const TidReporterArgument &); 66 void operator=(const TidReporterArgument &); 67}; 68 69class ThreadListerTest : public ::testing::Test { 70 protected: 71 virtual void SetUp() { 72 pthread_t pthread_id; 73 pid_t tid; 74 for (uptr i = 0; i < kThreadCount; i++) { 75 SpawnTidReporter(&pthread_id, &tid); 76 pthread_ids_.push_back(pthread_id); 77 tids_.push_back(tid); 78 } 79 } 80 81 virtual void TearDown() { 82 pthread_mutex_lock(&thread_arg.terminate_thread_mutex); 83 thread_arg.terminate_thread = true; 84 pthread_cond_broadcast(&thread_arg.terminate_thread_cond); 85 pthread_mutex_unlock(&thread_arg.terminate_thread_mutex); 86 for (uptr i = 0; i < pthread_ids_.size(); i++) 87 pthread_join(pthread_ids_[i], NULL); 88 } 89 90 void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid); 91 92 static const uptr kThreadCount = 20; 93 94 std::vector<pthread_t> pthread_ids_; 95 std::vector<pid_t> tids_; 96 97 TidReporterArgument thread_arg; 98}; 99 100// Writes its TID once to reported_tid and waits until signaled to terminate. 101void *TidReporterThread(void *argument) { 102 TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument); 103 pthread_mutex_lock(&arg->tid_reported_mutex); 104 arg->reported_tid = GetTid(); 105 pthread_cond_broadcast(&arg->tid_reported_cond); 106 pthread_mutex_unlock(&arg->tid_reported_mutex); 107 108 pthread_mutex_lock(&arg->terminate_thread_mutex); 109 while (!arg->terminate_thread) 110 pthread_cond_wait(&arg->terminate_thread_cond, 111 &arg->terminate_thread_mutex); 112 pthread_mutex_unlock(&arg->terminate_thread_mutex); 113 return NULL; 114} 115 116void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, 117 pid_t *tid) { 118 pthread_mutex_lock(&thread_arg.tid_reported_mutex); 119 thread_arg.reported_tid = -1; 120 ASSERT_EQ(0, pthread_create(pthread_id, NULL, 121 TidReporterThread, 122 &thread_arg)); 123 while (thread_arg.reported_tid == -1) 124 pthread_cond_wait(&thread_arg.tid_reported_cond, 125 &thread_arg.tid_reported_mutex); 126 pthread_mutex_unlock(&thread_arg.tid_reported_mutex); 127 *tid = thread_arg.reported_tid; 128} 129 130static std::vector<pid_t> ReadTidsToVector(ThreadLister *thread_lister) { 131 std::vector<pid_t> listed_tids; 132 pid_t tid; 133 while ((tid = thread_lister->GetNextTID()) >= 0) 134 listed_tids.push_back(tid); 135 EXPECT_FALSE(thread_lister->error()); 136 return listed_tids; 137} 138 139static bool Includes(std::vector<pid_t> first, std::vector<pid_t> second) { 140 std::sort(first.begin(), first.end()); 141 std::sort(second.begin(), second.end()); 142 return std::includes(first.begin(), first.end(), 143 second.begin(), second.end()); 144} 145 146static bool HasElement(std::vector<pid_t> vector, pid_t element) { 147 return std::find(vector.begin(), vector.end(), element) != vector.end(); 148} 149 150// ThreadLister's output should include the current thread's TID and the TID of 151// every thread we spawned. 152TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) { 153 pid_t self_tid = GetTid(); 154 ThreadLister thread_lister(getpid()); 155 std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); 156 ASSERT_TRUE(HasElement(listed_tids, self_tid)); 157 ASSERT_TRUE(Includes(listed_tids, tids_)); 158} 159 160// Calling Reset() should not cause ThreadLister to forget any threads it's 161// supposed to know about. 162TEST_F(ThreadListerTest, ResetDoesNotForgetThreads) { 163 ThreadLister thread_lister(getpid()); 164 165 // Run the loop body twice, because Reset() might behave differently if called 166 // on a freshly created object. 167 for (uptr i = 0; i < 2; i++) { 168 thread_lister.Reset(); 169 std::vector<pid_t> listed_tids = ReadTidsToVector(&thread_lister); 170 ASSERT_TRUE(Includes(listed_tids, tids_)); 171 } 172} 173 174// If new threads have spawned during ThreadLister object's lifetime, calling 175// Reset() should cause ThreadLister to recognize their existence. 176TEST_F(ThreadListerTest, ResetMakesNewThreadsKnown) { 177 ThreadLister thread_lister(getpid()); 178 std::vector<pid_t> threads_before_extra = ReadTidsToVector(&thread_lister); 179 180 pthread_t extra_pthread_id; 181 pid_t extra_tid; 182 SpawnTidReporter(&extra_pthread_id, &extra_tid); 183 // Register the new thread so it gets terminated in TearDown(). 184 pthread_ids_.push_back(extra_pthread_id); 185 186 // It would be very bizarre if the new TID had been listed before we even 187 // spawned that thread, but it would also cause a false success in this test, 188 // so better check for that. 189 ASSERT_FALSE(HasElement(threads_before_extra, extra_tid)); 190 191 thread_lister.Reset(); 192 193 std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister); 194 ASSERT_TRUE(HasElement(threads_after_extra, extra_tid)); 195} 196 197TEST(SanitizerCommon, SetEnvTest) { 198 const char kEnvName[] = "ENV_FOO"; 199 SetEnv(kEnvName, "value"); 200 EXPECT_STREQ("value", getenv(kEnvName)); 201 unsetenv(kEnvName); 202 EXPECT_EQ(0, getenv(kEnvName)); 203} 204 205#ifdef __x86_64__ 206// libpthread puts the thread descriptor (%fs:0x0) at the end of stack space. 207void *thread_descriptor_test_func(void *arg) { 208 uptr fs; 209 arch_prctl(ARCH_GET_FS, &fs); 210 pthread_attr_t attr; 211 pthread_getattr_np(pthread_self(), &attr); 212 void *stackaddr; 213 uptr stacksize; 214 pthread_attr_getstack(&attr, &stackaddr, &stacksize); 215 return (void *)((uptr)stackaddr + stacksize - fs); 216} 217 218TEST(SanitizerLinux, ThreadDescriptorSize) { 219 pthread_t tid; 220 void *result; 221 pthread_create(&tid, 0, thread_descriptor_test_func, 0); 222 ASSERT_EQ(0, pthread_join(tid, &result)); 223 EXPECT_EQ((uptr)result, ThreadDescriptorSize()); 224} 225#endif 226 227TEST(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} // namespace __sanitizer 252 253#endif // SANITIZER_LINUX 254