xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp (revision e12fbdf8775f54580b6a9a77b53c31faddece841)
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 <pthread.h>
17 #  include <sched.h>
18 #  include <stdlib.h>
19 
20 #  include <algorithm>
21 #  include <vector>
22 
23 #  include "gtest/gtest.h"
24 #  include "sanitizer_common/sanitizer_common.h"
25 #  include "sanitizer_common/sanitizer_file.h"
26 #  include "sanitizer_common/sanitizer_linux.h"
27 
28 namespace __sanitizer {
29 
30 struct 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   tid_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 
61 class ThreadListerTest : public ::testing::Test {
62  protected:
63   virtual void SetUp() {
64     pthread_t pthread_id;
65     tid_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, tid_t *tid);
83 
84   static const uptr kThreadCount = 20;
85 
86   std::vector<pthread_t> pthread_ids_;
87   std::vector<tid_t> tids_;
88 
89   TidReporterArgument thread_arg;
90 };
91 
92 // Writes its TID once to reported_tid and waits until signaled to terminate.
93 void *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 
108 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) {
109   pthread_mutex_lock(&thread_arg.tid_reported_mutex);
110   thread_arg.reported_tid = -1;
111   ASSERT_EQ(0,
112             pthread_create(pthread_id, NULL, TidReporterThread, &thread_arg));
113   while (thread_arg.reported_tid == (tid_t)(-1))
114     pthread_cond_wait(&thread_arg.tid_reported_cond,
115                       &thread_arg.tid_reported_mutex);
116   pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
117   *tid = thread_arg.reported_tid;
118 }
119 
120 static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) {
121   std::vector<tid_t> listed_tids;
122   InternalMmapVector<tid_t> threads(128);
123   EXPECT_TRUE(thread_lister->ListThreads(&threads));
124   return std::vector<tid_t>(threads.begin(), threads.end());
125 }
126 
127 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {
128   std::sort(first.begin(), first.end());
129   std::sort(second.begin(), second.end());
130   return std::includes(first.begin(), first.end(), second.begin(),
131                        second.end());
132 }
133 
134 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
135   return std::find(vector.begin(), vector.end(), element) != vector.end();
136 }
137 
138 // ThreadLister's output should include the current thread's TID and the TID of
139 // every thread we spawned.
140 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
141   tid_t self_tid = GetTid();
142   ThreadLister thread_lister(getpid());
143   std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
144   ASSERT_TRUE(HasElement(listed_tids, self_tid));
145   ASSERT_TRUE(Includes(listed_tids, tids_));
146 
147   ASSERT_NE(nullptr, thread_lister.LoadStatus(self_tid));
148   for (auto tid : tids_) ASSERT_NE(nullptr, thread_lister.LoadStatus(tid));
149 }
150 
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.
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 
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
192 // libpthread puts the thread descriptor at the end of stack space.
193 void *thread_descriptor_size_test_func(void *arg) {
194   uptr descr_addr = (uptr)pthread_self();
195   pthread_attr_t attr;
196   pthread_getattr_np(pthread_self(), &attr);
197   void *stackaddr;
198   size_t stacksize;
199   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
200   return (void *)((uptr)stackaddr + stacksize - descr_addr);
201 }
202 
203 TEST(SanitizerLinux, ThreadDescriptorSize) {
204   pthread_t tid;
205   void *result;
206   ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
207   ASSERT_EQ(0, pthread_join(tid, &result));
208   InitTlsSize();
209   EXPECT_EQ((uptr)result, ThreadDescriptorSize());
210 }
211 #  endif
212 
213 TEST(SanitizerCommon, LibraryNameIs) {
214   EXPECT_FALSE(LibraryNameIs("", ""));
215 
216   char full_name[256];
217   const char *paths[] = {"", "/", "/path/to/"};
218   const char *suffixes[] = {"", "-linux", ".1.2", "-linux.1.2"};
219   const char *base_names[] = {"lib", "lib.0", "lib-i386"};
220   const char *wrong_names[] = {"", "lib.9", "lib-x86_64"};
221   for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
222     for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
223       for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
224         internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
225                           paths[i], base_names[k], suffixes[j]);
226         EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
227             << "Full name " << full_name << " doesn't match base name "
228             << base_names[k];
229         for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
230           EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
231               << "Full name " << full_name << " matches base name "
232               << wrong_names[m];
233       }
234     }
235 }
236 
237 #  if defined(__mips64)
238 // Effectively, this is a test for ThreadDescriptorSize() which is used to
239 // compute ThreadSelf().
240 TEST(SanitizerLinux, ThreadSelfTest) {
241   ASSERT_EQ(pthread_self(), ThreadSelf());
242 }
243 #  endif
244 
245 TEST(SanitizerCommon, StartSubprocessTest) {
246   int pipe_fds[2];
247   ASSERT_EQ(0, pipe(pipe_fds));
248 #  if SANITIZER_ANDROID
249   const char *shell = "/system/bin/sh";
250 #  else
251   const char *shell = "/bin/sh";
252 #  endif
253   const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
254   int pid = StartSubprocess(shell, argv, GetEnviron(),
255                             /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
256   ASSERT_GT(pid, 0);
257 
258   // wait for process to finish.
259   while (IsProcessRunning(pid)) {
260   }
261   ASSERT_FALSE(IsProcessRunning(pid));
262 
263   char buffer[256];
264   {
265     char *ptr = buffer;
266     uptr bytes_read;
267     while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
268       if (!bytes_read) {
269         break;
270       }
271       ptr += bytes_read;
272     }
273     ASSERT_EQ(5, ptr - buffer);
274     *ptr = 0;
275   }
276   ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
277   internal_close(pipe_fds[0]);
278 }
279 
280 }  // namespace __sanitizer
281 
282 #endif  // SANITIZER_LINUX
283