Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / compiler-rt / lib / sanitizer_common / tests / sanitizer_linux_test.cpp
blob025cba922d2dfacaaf2152b9d22a51b737c8ac2a
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
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
14 #if SANITIZER_LINUX
16 #include "sanitizer_common/sanitizer_linux.h"
18 #include "sanitizer_common/sanitizer_common.h"
19 #include "sanitizer_common/sanitizer_file.h"
20 #include "gtest/gtest.h"
22 #include <pthread.h>
23 #include <sched.h>
24 #include <stdlib.h>
26 #include <algorithm>
27 #include <vector>
29 namespace __sanitizer {
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;
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);
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;
56 private:
57 // Disallow evil constructors
58 TidReporterArgument(const TidReporterArgument &);
59 void operator=(const TidReporterArgument &);
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);
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);
83 void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid);
85 static const uptr kThreadCount = 20;
87 std::vector<pthread_t> pthread_ids_;
88 std::vector<tid_t> tids_;
90 TidReporterArgument thread_arg;
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);
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;
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;
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());
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());
136 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
137 return std::find(vector.begin(), vector.end(), element) != vector.end();
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_));
150 TEST_F(ThreadListerTest, DoNotForgetThreads) {
151 ThreadLister thread_lister(getpid());
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_));
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);
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);
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));
178 std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
179 ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
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));
190 #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
191 // libpthread puts the thread descriptor at the end of stack space.
192 void *thread_descriptor_size_test_func(void *arg) {
193 uptr descr_addr = (uptr)pthread_self();
194 pthread_attr_t attr;
195 pthread_getattr_np(pthread_self(), &attr);
196 void *stackaddr;
197 size_t stacksize;
198 pthread_attr_getstack(&attr, &stackaddr, &stacksize);
199 return (void *)((uptr)stackaddr + stacksize - descr_addr);
202 TEST(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());
209 #endif
211 TEST(SanitizerCommon, LibraryNameIs) {
212 EXPECT_FALSE(LibraryNameIs("", ""));
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];
235 #if defined(__mips64)
236 // Effectively, this is a test for ThreadDescriptorSize() which is used to
237 // compute ThreadSelf().
238 TEST(SanitizerLinux, ThreadSelfTest) {
239 ASSERT_EQ(pthread_self(), ThreadSelf());
241 #endif
243 TEST(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);
256 // wait for process to finish.
257 while (IsProcessRunning(pid)) {
259 ASSERT_FALSE(IsProcessRunning(pid));
261 char buffer[256];
263 char *ptr = buffer;
264 uptr bytes_read;
265 while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
266 if (!bytes_read) {
267 break;
269 ptr += bytes_read;
271 ASSERT_EQ(5, ptr - buffer);
272 *ptr = 0;
274 ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
275 internal_close(pipe_fds[0]);
278 } // namespace __sanitizer
280 #endif // SANITIZER_LINUX