• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
TidReporterArgument__sanitizer::TidReporterArgument32   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 
~TidReporterArgument__sanitizer::TidReporterArgument40   ~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:
SetUp()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 
TearDown()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.
TidReporterThread(void * argument)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 
SpawnTidReporter(pthread_t * pthread_id,pid_t * tid)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 
ReadTidsToVector(ThreadLister * thread_lister)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 
Includes(std::vector<pid_t> first,std::vector<pid_t> second)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 
HasElement(std::vector<pid_t> vector,pid_t element)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.
TEST_F(ThreadListerTest,ThreadListerSeesAllSpawnedThreads)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.
TEST_F(ThreadListerTest,ResetDoesNotForgetThreads)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.
TEST_F(ThreadListerTest,ResetMakesNewThreadsKnown)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 
TEST(SanitizerCommon,SetEnvTest)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__)
thread_self_offset_test_func(void * arg)199 void *thread_self_offset_test_func(void *arg) {
200   bool result =
201       *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
202   return (void *)result;
203 }
204 
TEST(SanitizerLinux,ThreadSelfOffset)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.
thread_descriptor_size_test_func(void * arg)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 
TEST(SanitizerLinux,ThreadDescriptorSize)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 
TEST(SanitizerCommon,LibraryNameIs)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