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
29namespace __sanitizer {
30
31struct TidReporterArgument {
32 TidReporterArgument() {
33 pthread_mutex_init(mutex: &terminate_thread_mutex, NULL);
34 pthread_mutex_init(mutex: &tid_reported_mutex, NULL);
35 pthread_cond_init(cond: &terminate_thread_cond, NULL);
36 pthread_cond_init(cond: &tid_reported_cond, NULL);
37 terminate_thread = false;
38 }
39
40 ~TidReporterArgument() {
41 pthread_mutex_destroy(mutex: &terminate_thread_mutex);
42 pthread_mutex_destroy(mutex: &tid_reported_mutex);
43 pthread_cond_destroy(cond: &terminate_thread_cond);
44 pthread_cond_destroy(cond: &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
62class 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: &pthread_id, tid: &tid);
69 pthread_ids_.push_back(pthread_id);
70 tids_.push_back(tid);
71 }
72 }
73
74 virtual void TearDown() {
75 pthread_mutex_lock(mutex: &thread_arg.terminate_thread_mutex);
76 thread_arg.terminate_thread = true;
77 pthread_cond_broadcast(cond: &thread_arg.terminate_thread_cond);
78 pthread_mutex_unlock(mutex: &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.
94void *TidReporterThread(void *argument) {
95 TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
96 pthread_mutex_lock(mutex: &arg->tid_reported_mutex);
97 arg->reported_tid = GetTid();
98 pthread_cond_broadcast(cond: &arg->tid_reported_cond);
99 pthread_mutex_unlock(mutex: &arg->tid_reported_mutex);
100
101 pthread_mutex_lock(mutex: &arg->terminate_thread_mutex);
102 while (!arg->terminate_thread)
103 pthread_cond_wait(cond: &arg->terminate_thread_cond,
104 mutex: &arg->terminate_thread_mutex);
105 pthread_mutex_unlock(mutex: &arg->terminate_thread_mutex);
106 return NULL;
107}
108
109void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) {
110 pthread_mutex_lock(mutex: &thread_arg.tid_reported_mutex);
111 thread_arg.reported_tid = -1;
112 ASSERT_EQ(0, pthread_create(newthread: pthread_id, NULL,
113 start_routine: TidReporterThread,
114 arg: &thread_arg));
115 while (thread_arg.reported_tid == (tid_t)(-1))
116 pthread_cond_wait(cond: &thread_arg.tid_reported_cond,
117 mutex: &thread_arg.tid_reported_mutex);
118 pthread_mutex_unlock(mutex: &thread_arg.tid_reported_mutex);
119 *tid = thread_arg.reported_tid;
120}
121
122static 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
129static 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
136static 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.
142TEST_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
150TEST_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.
163TEST_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
182TEST(SanitizerCommon, SetEnvTest) {
183 const char kEnvName[] = "ENV_FOO";
184 SetEnv(name: kEnvName, value: "value");
185 EXPECT_STREQ("value", getenv(name: kEnvName));
186 unsetenv(name: kEnvName);
187 EXPECT_EQ(0, getenv(name: kEnvName));
188}
189
190#if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
191// libpthread puts the thread descriptor at the end of stack space.
192void *thread_descriptor_size_test_func(void *arg) {
193 uptr descr_addr = (uptr)pthread_self();
194 pthread_attr_t attr;
195 pthread_getattr_np(th: pthread_self(), attr: &attr);
196 void *stackaddr;
197 size_t stacksize;
198 pthread_attr_getstack(attr: &attr, stackaddr: &stackaddr, stacksize: &stacksize);
199 return (void *)((uptr)stackaddr + stacksize - descr_addr);
200}
201
202TEST(SanitizerLinux, ThreadDescriptorSize) {
203 pthread_t tid;
204 void *result;
205 ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
206 ASSERT_EQ(0, pthread_join(tid, &result));
207 EXPECT_EQ((uptr)result, ThreadDescriptorSize());
208}
209#endif
210
211TEST(SanitizerCommon, LibraryNameIs) {
212 EXPECT_FALSE(LibraryNameIs("", ""));
213
214 char full_name[256];
215 const char *paths[] = { "", "/", "/path/to/" };
216 const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
217 const char *base_names[] = { "lib", "lib.0", "lib-i386" };
218 const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
219 for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
220 for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
221 for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
222 internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
223 paths[i], base_names[k], suffixes[j]);
224 EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
225 << "Full name " << full_name
226 << " doesn't match base name " << base_names[k];
227 for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
228 EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
229 << "Full name " << full_name
230 << " matches base name " << wrong_names[m];
231 }
232 }
233}
234
235#if defined(__mips64)
236// Effectively, this is a test for ThreadDescriptorSize() which is used to
237// compute ThreadSelf().
238TEST(SanitizerLinux, ThreadSelfTest) {
239 ASSERT_EQ(pthread_self(), ThreadSelf());
240}
241#endif
242
243TEST(SanitizerCommon, StartSubprocessTest) {
244 int pipe_fds[2];
245 ASSERT_EQ(0, pipe(pipe_fds));
246#if SANITIZER_ANDROID
247 const char *shell = "/system/bin/sh";
248#else
249 const char *shell = "/bin/sh";
250#endif
251 const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
252 int pid = StartSubprocess(shell, argv, GetEnviron(),
253 /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
254 ASSERT_GT(pid, 0);
255
256 // wait for process to finish.
257 while (IsProcessRunning(pid)) {
258 }
259 ASSERT_FALSE(IsProcessRunning(pid));
260
261 char buffer[256];
262 {
263 char *ptr = buffer;
264 uptr bytes_read;
265 while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
266 if (!bytes_read) {
267 break;
268 }
269 ptr += bytes_read;
270 }
271 ASSERT_EQ(5, ptr - buffer);
272 *ptr = 0;
273 }
274 ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
275 internal_close(pipe_fds[0]);
276}
277
278} // namespace __sanitizer
279
280#endif // SANITIZER_LINUX
281

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp