xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 //===-- sanitizer_linux_test.cpp ------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Tests for sanitizer_linux.h
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "sanitizer_common/sanitizer_platform.h"
14 #if SANITIZER_LINUX
15 
16 #include "sanitizer_common/sanitizer_linux.h"
17 
18 #include "sanitizer_common/sanitizer_common.h"
19 #include "sanitizer_common/sanitizer_file.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 {
32   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 
40   ~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   tid_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:
64   virtual void SetUp() {
65     pthread_t pthread_id;
66     tid_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 
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, tid_t *tid);
84 
85   static const uptr kThreadCount = 20;
86 
87   std::vector<pthread_t> pthread_ids_;
88   std::vector<tid_t> tids_;
89 
90   TidReporterArgument thread_arg;
91 };
92 
93 // Writes its TID once to reported_tid and waits until signaled to terminate.
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 
109 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_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 == (tid_t)(-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 
122 static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) {
123   std::vector<tid_t> listed_tids;
124   InternalMmapVector<tid_t> threads(128);
125   EXPECT_TRUE(thread_lister->ListThreads(&threads));
126   return std::vector<tid_t>(threads.begin(), threads.end());
127 }
128 
129 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {
130   std::sort(first.begin(), first.end());
131   std::sort(second.begin(), second.end());
132   return std::includes(first.begin(), first.end(),
133                        second.begin(), second.end());
134 }
135 
136 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
137   return std::find(vector.begin(), vector.end(), element) != vector.end();
138 }
139 
140 // ThreadLister's output should include the current thread's TID and the TID of
141 // every thread we spawned.
142 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
143   tid_t self_tid = GetTid();
144   ThreadLister thread_lister(getpid());
145   std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
146   ASSERT_TRUE(HasElement(listed_tids, self_tid));
147   ASSERT_TRUE(Includes(listed_tids, tids_));
148 }
149 
150 TEST_F(ThreadListerTest, DoNotForgetThreads) {
151   ThreadLister thread_lister(getpid());
152 
153   // Run the loop body twice, because ThreadLister might behave differently if
154   // called on a freshly created object.
155   for (uptr i = 0; i < 2; i++) {
156     std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
157     ASSERT_TRUE(Includes(listed_tids, tids_));
158   }
159 }
160 
161 // If new threads have spawned during ThreadLister object's lifetime, calling
162 // relisting should cause ThreadLister to recognize their existence.
163 TEST_F(ThreadListerTest, NewThreads) {
164   ThreadLister thread_lister(getpid());
165   std::vector<tid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
166 
167   pthread_t extra_pthread_id;
168   tid_t extra_tid;
169   SpawnTidReporter(&extra_pthread_id, &extra_tid);
170   // Register the new thread so it gets terminated in TearDown().
171   pthread_ids_.push_back(extra_pthread_id);
172 
173   // It would be very bizarre if the new TID had been listed before we even
174   // spawned that thread, but it would also cause a false success in this test,
175   // so better check for that.
176   ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
177 
178   std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
179   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
180 }
181 
182 TEST(SanitizerCommon, SetEnvTest) {
183   const char kEnvName[] = "ENV_FOO";
184   SetEnv(kEnvName, "value");
185   EXPECT_STREQ("value", getenv(kEnvName));
186   unsetenv(kEnvName);
187   EXPECT_EQ(0, getenv(kEnvName));
188 }
189 
190 #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
191 void *thread_self_offset_test_func(void *arg) {
192   bool result =
193       *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
194   return (void *)result;
195 }
196 
197 TEST(SanitizerLinux, ThreadSelfOffset) {
198   EXPECT_TRUE((bool)thread_self_offset_test_func(0));
199   pthread_t tid;
200   void *result;
201   ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
202   ASSERT_EQ(0, pthread_join(tid, &result));
203   EXPECT_TRUE((bool)result);
204 }
205 
206 // libpthread puts the thread descriptor at the end of stack space.
207 void *thread_descriptor_size_test_func(void *arg) {
208   uptr descr_addr = ThreadSelf();
209   pthread_attr_t attr;
210   pthread_getattr_np(pthread_self(), &attr);
211   void *stackaddr;
212   size_t stacksize;
213   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
214   return (void *)((uptr)stackaddr + stacksize - descr_addr);
215 }
216 
217 TEST(SanitizerLinux, ThreadDescriptorSize) {
218   pthread_t tid;
219   void *result;
220   ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
221   ASSERT_EQ(0, pthread_join(tid, &result));
222   EXPECT_EQ((uptr)result, ThreadDescriptorSize());
223 }
224 #endif
225 
226 TEST(SanitizerCommon, LibraryNameIs) {
227   EXPECT_FALSE(LibraryNameIs("", ""));
228 
229   char full_name[256];
230   const char *paths[] = { "", "/", "/path/to/" };
231   const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
232   const char *base_names[] = { "lib", "lib.0", "lib-i386" };
233   const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
234   for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
235     for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
236       for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
237         internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
238                           paths[i], base_names[k], suffixes[j]);
239         EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
240             << "Full name " << full_name
241             << " doesn't match base name " << base_names[k];
242         for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
243           EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
244             << "Full name " << full_name
245             << " matches base name " << wrong_names[m];
246       }
247     }
248 }
249 
250 #if defined(__mips64)
251 // Effectively, this is a test for ThreadDescriptorSize() which is used to
252 // compute ThreadSelf().
253 TEST(SanitizerLinux, ThreadSelfTest) {
254   ASSERT_EQ(pthread_self(), ThreadSelf());
255 }
256 #endif
257 
258 TEST(SanitizerCommon, StartSubprocessTest) {
259   int pipe_fds[2];
260   ASSERT_EQ(0, pipe(pipe_fds));
261 #if SANITIZER_ANDROID
262   const char *shell = "/system/bin/sh";
263 #else
264   const char *shell = "/bin/sh";
265 #endif
266   const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
267   int pid = StartSubprocess(shell, argv, GetEnviron(),
268                             /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
269   ASSERT_GT(pid, 0);
270 
271   // wait for process to finish.
272   while (IsProcessRunning(pid)) {
273   }
274   ASSERT_FALSE(IsProcessRunning(pid));
275 
276   char buffer[256];
277   {
278     char *ptr = buffer;
279     uptr bytes_read;
280     while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
281       if (!bytes_read) {
282         break;
283       }
284       ptr += bytes_read;
285     }
286     ASSERT_EQ(5, ptr - buffer);
287     *ptr = 0;
288   }
289   ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
290   internal_close(pipe_fds[0]);
291 }
292 
293 }  // namespace __sanitizer
294 
295 #endif  // SANITIZER_LINUX
296