1 //===-- sanitizer_linux_test.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Tests for sanitizer_linux.h
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
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"
28 namespace __sanitizer
{
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;
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
);
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
;
56 // Disallow evil constructors
57 TidReporterArgument(const TidReporterArgument
&);
58 void operator=(const TidReporterArgument
&);
61 class ThreadListerTest
: public ::testing::Test
{
63 virtual void SetUp() {
66 for (uptr i
= 0; i
< kThreadCount
; i
++) {
67 SpawnTidReporter(&pthread_id
, &tid
);
68 pthread_ids_
.push_back(pthread_id
);
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
);
82 void SpawnTidReporter(pthread_t
*pthread_id
, tid_t
*tid
);
84 static const uptr kThreadCount
= 20;
86 std::vector
<pthread_t
> pthread_ids_
;
87 std::vector
<tid_t
> tids_
;
89 TidReporterArgument thread_arg
;
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
);
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
);
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;
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
;
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());
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(),
134 static bool HasElement(const std::vector
<tid_t
> &vector
, tid_t element
) {
135 return std::find(vector
.begin(), vector
.end(), element
) != vector
.end();
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_
));
147 ASSERT_NE(nullptr, thread_lister
.LoadStatus(self_tid
));
148 for (auto tid
: tids_
) ASSERT_NE(nullptr, thread_lister
.LoadStatus(tid
));
151 TEST_F(ThreadListerTest
, DoNotForgetThreads
) {
152 ThreadLister
thread_lister(getpid());
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_
));
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
);
168 pthread_t extra_pthread_id
;
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
);
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
));
179 std::vector
<tid_t
> threads_after_extra
= ReadTidsToVector(&thread_lister
);
180 ASSERT_TRUE(HasElement(threads_after_extra
, extra_tid
));
183 TEST(SanitizerCommon
, SetEnvTest
) {
184 const char kEnvName
[] = "ENV_FOO";
185 SetEnv(kEnvName
, "value");
186 EXPECT_STREQ("value", getenv(kEnvName
));
188 EXPECT_EQ(0, getenv(kEnvName
));
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();
196 pthread_getattr_np(pthread_self(), &attr
);
199 pthread_attr_getstack(&attr
, &stackaddr
, &stacksize
);
200 return (void *)((uptr
)stackaddr
+ stacksize
- descr_addr
);
203 TEST(SanitizerLinux
, ThreadDescriptorSize
) {
206 ASSERT_EQ(0, pthread_create(&tid
, 0, thread_descriptor_size_test_func
, 0));
207 ASSERT_EQ(0, pthread_join(tid
, &result
));
209 EXPECT_EQ((uptr
)result
, ThreadDescriptorSize());
213 TEST(SanitizerCommon
, LibraryNameIs
) {
214 EXPECT_FALSE(LibraryNameIs("", ""));
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 "
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 "
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());
245 TEST(SanitizerCommon
, StartSubprocessTest
) {
247 ASSERT_EQ(0, pipe(pipe_fds
));
248 # if SANITIZER_ANDROID
249 const char *shell
= "/system/bin/sh";
251 const char *shell
= "/bin/sh";
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]);
258 // wait for process to finish.
259 while (IsProcessRunning(pid
)) {
261 ASSERT_FALSE(IsProcessRunning(pid
));
267 while (ReadFromFile(pipe_fds
[0], ptr
, 256, &bytes_read
)) {
273 ASSERT_EQ(5, ptr
- buffer
);
276 ASSERT_EQ(0, strcmp(buffer
, "hello")) << "Buffer: " << buffer
;
277 internal_close(pipe_fds
[0]);
280 } // namespace __sanitizer
282 #endif // SANITIZER_LINUX