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