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