xref: /netbsd-src/sys/external/bsd/compiler_rt/dist/lib/sanitizer_common/tests/sanitizer_linux_test.cc (revision a7c257b03e4462df2b1020128fb82716512d7856)
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 "sanitizer_common/sanitizer_file.h"
21 #include "gtest/gtest.h"
22 
23 #include <pthread.h>
24 #include <sched.h>
25 #include <stdlib.h>
26 
27 #include <algorithm>
28 #include <vector>
29 
30 namespace __sanitizer {
31 
32 struct TidReporterArgument {
TidReporterArgument__sanitizer::TidReporterArgument33   TidReporterArgument() {
34     pthread_mutex_init(&terminate_thread_mutex, NULL);
35     pthread_mutex_init(&tid_reported_mutex, NULL);
36     pthread_cond_init(&terminate_thread_cond, NULL);
37     pthread_cond_init(&tid_reported_cond, NULL);
38     terminate_thread = false;
39   }
40 
~TidReporterArgument__sanitizer::TidReporterArgument41   ~TidReporterArgument() {
42     pthread_mutex_destroy(&terminate_thread_mutex);
43     pthread_mutex_destroy(&tid_reported_mutex);
44     pthread_cond_destroy(&terminate_thread_cond);
45     pthread_cond_destroy(&tid_reported_cond);
46   }
47 
48   tid_t reported_tid;
49   // For signaling to spawned threads that they should terminate.
50   pthread_cond_t terminate_thread_cond;
51   pthread_mutex_t terminate_thread_mutex;
52   bool terminate_thread;
53   // For signaling to main thread that a child thread has reported its tid.
54   pthread_cond_t tid_reported_cond;
55   pthread_mutex_t tid_reported_mutex;
56 
57  private:
58   // Disallow evil constructors
59   TidReporterArgument(const TidReporterArgument &);
60   void operator=(const TidReporterArgument &);
61 };
62 
63 class ThreadListerTest : public ::testing::Test {
64  protected:
SetUp()65   virtual void SetUp() {
66     pthread_t pthread_id;
67     tid_t tid;
68     for (uptr i = 0; i < kThreadCount; i++) {
69       SpawnTidReporter(&pthread_id, &tid);
70       pthread_ids_.push_back(pthread_id);
71       tids_.push_back(tid);
72     }
73   }
74 
TearDown()75   virtual void TearDown() {
76     pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
77     thread_arg.terminate_thread = true;
78     pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
79     pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
80     for (uptr i = 0; i < pthread_ids_.size(); i++)
81       pthread_join(pthread_ids_[i], NULL);
82   }
83 
84   void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid);
85 
86   static const uptr kThreadCount = 20;
87 
88   std::vector<pthread_t> pthread_ids_;
89   std::vector<tid_t> tids_;
90 
91   TidReporterArgument thread_arg;
92 };
93 
94 // Writes its TID once to reported_tid and waits until signaled to terminate.
TidReporterThread(void * argument)95 void *TidReporterThread(void *argument) {
96   TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
97   pthread_mutex_lock(&arg->tid_reported_mutex);
98   arg->reported_tid = GetTid();
99   pthread_cond_broadcast(&arg->tid_reported_cond);
100   pthread_mutex_unlock(&arg->tid_reported_mutex);
101 
102   pthread_mutex_lock(&arg->terminate_thread_mutex);
103   while (!arg->terminate_thread)
104     pthread_cond_wait(&arg->terminate_thread_cond,
105                       &arg->terminate_thread_mutex);
106   pthread_mutex_unlock(&arg->terminate_thread_mutex);
107   return NULL;
108 }
109 
SpawnTidReporter(pthread_t * pthread_id,tid_t * tid)110 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_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 == (tid_t)(-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<tid_t> ReadTidsToVector(ThreadLister *thread_lister) {
124   std::vector<tid_t> listed_tids;
125   InternalMmapVector<tid_t> threads(128);
126   EXPECT_TRUE(thread_lister->ListThreads(&threads));
127   return std::vector<tid_t>(threads.begin(), threads.end());
128 }
129 
Includes(std::vector<tid_t> first,std::vector<tid_t> second)130 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {
131   std::sort(first.begin(), first.end());
132   std::sort(second.begin(), second.end());
133   return std::includes(first.begin(), first.end(),
134                        second.begin(), second.end());
135 }
136 
HasElement(const std::vector<tid_t> & vector,tid_t element)137 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
138   return std::find(vector.begin(), vector.end(), element) != vector.end();
139 }
140 
141 // ThreadLister's output should include the current thread's TID and the TID of
142 // every thread we spawned.
TEST_F(ThreadListerTest,ThreadListerSeesAllSpawnedThreads)143 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
144   tid_t self_tid = GetTid();
145   ThreadLister thread_lister(getpid());
146   std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
147   ASSERT_TRUE(HasElement(listed_tids, self_tid));
148   ASSERT_TRUE(Includes(listed_tids, tids_));
149 }
150 
TEST_F(ThreadListerTest,DoNotForgetThreads)151 TEST_F(ThreadListerTest, DoNotForgetThreads) {
152   ThreadLister thread_lister(getpid());
153 
154   // Run the loop body twice, because ThreadLister might behave differently if
155   // called on a freshly created object.
156   for (uptr i = 0; i < 2; i++) {
157     std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
158     ASSERT_TRUE(Includes(listed_tids, tids_));
159   }
160 }
161 
162 // If new threads have spawned during ThreadLister object's lifetime, calling
163 // relisting should cause ThreadLister to recognize their existence.
TEST_F(ThreadListerTest,NewThreads)164 TEST_F(ThreadListerTest, NewThreads) {
165   ThreadLister thread_lister(getpid());
166   std::vector<tid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
167 
168   pthread_t extra_pthread_id;
169   tid_t extra_tid;
170   SpawnTidReporter(&extra_pthread_id, &extra_tid);
171   // Register the new thread so it gets terminated in TearDown().
172   pthread_ids_.push_back(extra_pthread_id);
173 
174   // It would be very bizarre if the new TID had been listed before we even
175   // spawned that thread, but it would also cause a false success in this test,
176   // so better check for that.
177   ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
178 
179   std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
180   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
181 }
182 
TEST(SanitizerCommon,SetEnvTest)183 TEST(SanitizerCommon, SetEnvTest) {
184   const char kEnvName[] = "ENV_FOO";
185   SetEnv(kEnvName, "value");
186   EXPECT_STREQ("value", getenv(kEnvName));
187   unsetenv(kEnvName);
188   EXPECT_EQ(0, getenv(kEnvName));
189 }
190 
191 #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
thread_self_offset_test_func(void * arg)192 void *thread_self_offset_test_func(void *arg) {
193   bool result =
194       *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
195   return (void *)result;
196 }
197 
TEST(SanitizerLinux,ThreadSelfOffset)198 TEST(SanitizerLinux, ThreadSelfOffset) {
199   EXPECT_TRUE((bool)thread_self_offset_test_func(0));
200   pthread_t tid;
201   void *result;
202   ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
203   ASSERT_EQ(0, pthread_join(tid, &result));
204   EXPECT_TRUE((bool)result);
205 }
206 
207 // libpthread puts the thread descriptor at the end of stack space.
thread_descriptor_size_test_func(void * arg)208 void *thread_descriptor_size_test_func(void *arg) {
209   uptr descr_addr = ThreadSelf();
210   pthread_attr_t attr;
211   pthread_getattr_np(pthread_self(), &attr);
212   void *stackaddr;
213   size_t stacksize;
214   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
215   return (void *)((uptr)stackaddr + stacksize - descr_addr);
216 }
217 
TEST(SanitizerLinux,ThreadDescriptorSize)218 TEST(SanitizerLinux, ThreadDescriptorSize) {
219   pthread_t tid;
220   void *result;
221   ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
222   ASSERT_EQ(0, pthread_join(tid, &result));
223   EXPECT_EQ((uptr)result, ThreadDescriptorSize());
224 }
225 #endif
226 
TEST(SanitizerCommon,LibraryNameIs)227 TEST(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 #if defined(__mips64)
252 // Effectively, this is a test for ThreadDescriptorSize() which is used to
253 // compute ThreadSelf().
TEST(SanitizerLinux,ThreadSelfTest)254 TEST(SanitizerLinux, ThreadSelfTest) {
255   ASSERT_EQ(pthread_self(), ThreadSelf());
256 }
257 #endif
258 
TEST(SanitizerCommon,StartSubprocessTest)259 TEST(SanitizerCommon, StartSubprocessTest) {
260   int pipe_fds[2];
261   ASSERT_EQ(0, pipe(pipe_fds));
262 #if SANITIZER_ANDROID
263   const char *shell = "/system/bin/sh";
264 #else
265   const char *shell = "/bin/sh";
266 #endif
267   const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
268   int pid = StartSubprocess(shell, argv,
269                             /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
270   ASSERT_GT(pid, 0);
271 
272   // wait for process to finish.
273   while (IsProcessRunning(pid)) {
274   }
275   ASSERT_FALSE(IsProcessRunning(pid));
276 
277   char buffer[256];
278   {
279     char *ptr = buffer;
280     uptr bytes_read;
281     while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
282       if (!bytes_read) {
283         break;
284       }
285       ptr += bytes_read;
286     }
287     ASSERT_EQ(5, ptr - buffer);
288     *ptr = 0;
289   }
290   ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
291   internal_close(pipe_fds[0]);
292 }
293 
294 }  // namespace __sanitizer
295 
296 #endif  // SANITIZER_LINUX
297