1 //===-- sanitizer_linux_test.cc -------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // Tests for sanitizer_linux.h
12 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common/sanitizer_platform.h"
17 #include "sanitizer_common/sanitizer_linux.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "gtest/gtest.h"
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
);
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
;
57 // Disallow evil constructors
58 TidReporterArgument(const TidReporterArgument
&);
59 void operator=(const TidReporterArgument
&);
62 class ThreadListerTest
: public ::testing::Test
{
64 virtual void SetUp() {
67 for (uptr i
= 0; i
< kThreadCount
; i
++) {
68 SpawnTidReporter(&pthread_id
, &tid
);
69 pthread_ids_
.push_back(pthread_id
);
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
, pid_t
*tid
);
85 static const uptr kThreadCount
= 20;
87 std::vector
<pthread_t
> pthread_ids_
;
88 std::vector
<pid_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
);
109 void ThreadListerTest::SpawnTidReporter(pthread_t
*pthread_id
,
111 pthread_mutex_lock(&thread_arg
.tid_reported_mutex
);
112 thread_arg
.reported_tid
= -1;
113 ASSERT_EQ(0, pthread_create(pthread_id
, NULL
,
116 while (thread_arg
.reported_tid
== -1)
117 pthread_cond_wait(&thread_arg
.tid_reported_cond
,
118 &thread_arg
.tid_reported_mutex
);
119 pthread_mutex_unlock(&thread_arg
.tid_reported_mutex
);
120 *tid
= thread_arg
.reported_tid
;
123 static std::vector
<pid_t
> ReadTidsToVector(ThreadLister
*thread_lister
) {
124 std::vector
<pid_t
> listed_tids
;
126 while ((tid
= thread_lister
->GetNextTID()) >= 0)
127 listed_tids
.push_back(tid
);
128 EXPECT_FALSE(thread_lister
->error());
132 static bool Includes(std::vector
<pid_t
> first
, std::vector
<pid_t
> second
) {
133 std::sort(first
.begin(), first
.end());
134 std::sort(second
.begin(), second
.end());
135 return std::includes(first
.begin(), first
.end(),
136 second
.begin(), second
.end());
139 static bool HasElement(std::vector
<pid_t
> vector
, pid_t element
) {
140 return std::find(vector
.begin(), vector
.end(), element
) != vector
.end();
143 // ThreadLister's output should include the current thread's TID and the TID of
144 // every thread we spawned.
145 TEST_F(ThreadListerTest
, ThreadListerSeesAllSpawnedThreads
) {
146 pid_t self_tid
= GetTid();
147 ThreadLister
thread_lister(getpid());
148 std::vector
<pid_t
> listed_tids
= ReadTidsToVector(&thread_lister
);
149 ASSERT_TRUE(HasElement(listed_tids
, self_tid
));
150 ASSERT_TRUE(Includes(listed_tids
, tids_
));
153 // Calling Reset() should not cause ThreadLister to forget any threads it's
154 // supposed to know about.
155 TEST_F(ThreadListerTest
, ResetDoesNotForgetThreads
) {
156 ThreadLister
thread_lister(getpid());
158 // Run the loop body twice, because Reset() might behave differently if called
159 // on a freshly created object.
160 for (uptr i
= 0; i
< 2; i
++) {
161 thread_lister
.Reset();
162 std::vector
<pid_t
> listed_tids
= ReadTidsToVector(&thread_lister
);
163 ASSERT_TRUE(Includes(listed_tids
, tids_
));
167 // If new threads have spawned during ThreadLister object's lifetime, calling
168 // Reset() should cause ThreadLister to recognize their existence.
169 TEST_F(ThreadListerTest
, ResetMakesNewThreadsKnown
) {
170 ThreadLister
thread_lister(getpid());
171 std::vector
<pid_t
> threads_before_extra
= ReadTidsToVector(&thread_lister
);
173 pthread_t extra_pthread_id
;
175 SpawnTidReporter(&extra_pthread_id
, &extra_tid
);
176 // Register the new thread so it gets terminated in TearDown().
177 pthread_ids_
.push_back(extra_pthread_id
);
179 // It would be very bizarre if the new TID had been listed before we even
180 // spawned that thread, but it would also cause a false success in this test,
181 // so better check for that.
182 ASSERT_FALSE(HasElement(threads_before_extra
, extra_tid
));
184 thread_lister
.Reset();
186 std::vector
<pid_t
> threads_after_extra
= ReadTidsToVector(&thread_lister
);
187 ASSERT_TRUE(HasElement(threads_after_extra
, extra_tid
));
190 TEST(SanitizerCommon
, SetEnvTest
) {
191 const char kEnvName
[] = "ENV_FOO";
192 SetEnv(kEnvName
, "value");
193 EXPECT_STREQ("value", getenv(kEnvName
));
195 EXPECT_EQ(0, getenv(kEnvName
));
198 #if defined(__x86_64__) || defined(__i386__)
199 void *thread_self_offset_test_func(void *arg
) {
201 *(uptr
*)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
202 return (void *)result
;
205 TEST(SanitizerLinux
, ThreadSelfOffset
) {
206 EXPECT_TRUE((bool)thread_self_offset_test_func(0));
209 ASSERT_EQ(0, pthread_create(&tid
, 0, thread_self_offset_test_func
, 0));
210 ASSERT_EQ(0, pthread_join(tid
, &result
));
211 EXPECT_TRUE((bool)result
);
214 // libpthread puts the thread descriptor at the end of stack space.
215 void *thread_descriptor_size_test_func(void *arg
) {
216 uptr descr_addr
= ThreadSelf();
218 pthread_getattr_np(pthread_self(), &attr
);
221 pthread_attr_getstack(&attr
, &stackaddr
, &stacksize
);
222 return (void *)((uptr
)stackaddr
+ stacksize
- descr_addr
);
225 TEST(SanitizerLinux
, ThreadDescriptorSize
) {
228 ASSERT_EQ(0, pthread_create(&tid
, 0, thread_descriptor_size_test_func
, 0));
229 ASSERT_EQ(0, pthread_join(tid
, &result
));
230 EXPECT_EQ((uptr
)result
, ThreadDescriptorSize());
234 TEST(SanitizerCommon
, LibraryNameIs
) {
235 EXPECT_FALSE(LibraryNameIs("", ""));
238 const char *paths
[] = { "", "/", "/path/to/" };
239 const char *suffixes
[] = { "", "-linux", ".1.2", "-linux.1.2" };
240 const char *base_names
[] = { "lib", "lib.0", "lib-i386" };
241 const char *wrong_names
[] = { "", "lib.9", "lib-x86_64" };
242 for (uptr i
= 0; i
< ARRAY_SIZE(paths
); i
++)
243 for (uptr j
= 0; j
< ARRAY_SIZE(suffixes
); j
++) {
244 for (uptr k
= 0; k
< ARRAY_SIZE(base_names
); k
++) {
245 internal_snprintf(full_name
, ARRAY_SIZE(full_name
), "%s%s%s.so",
246 paths
[i
], base_names
[k
], suffixes
[j
]);
247 EXPECT_TRUE(LibraryNameIs(full_name
, base_names
[k
]))
248 << "Full name " << full_name
249 << " doesn't match base name " << base_names
[k
];
250 for (uptr m
= 0; m
< ARRAY_SIZE(wrong_names
); m
++)
251 EXPECT_FALSE(LibraryNameIs(full_name
, wrong_names
[m
]))
252 << "Full name " << full_name
253 << " matches base name " << wrong_names
[m
];
258 } // namespace __sanitizer
260 #endif // SANITIZER_LINUX