xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/tests/sanitizer_linux_test.cpp (revision d89ec533011f513df1010f142a111086a0785f09)
13cab2bb3Spatrick //===-- sanitizer_linux_test.cpp ------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // Tests for sanitizer_linux.h
103cab2bb3Spatrick //
113cab2bb3Spatrick //===----------------------------------------------------------------------===//
123cab2bb3Spatrick 
133cab2bb3Spatrick #include "sanitizer_common/sanitizer_platform.h"
143cab2bb3Spatrick #if SANITIZER_LINUX
153cab2bb3Spatrick 
163cab2bb3Spatrick #include "sanitizer_common/sanitizer_linux.h"
173cab2bb3Spatrick 
183cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
193cab2bb3Spatrick #include "sanitizer_common/sanitizer_file.h"
203cab2bb3Spatrick #include "gtest/gtest.h"
213cab2bb3Spatrick 
223cab2bb3Spatrick #include <pthread.h>
233cab2bb3Spatrick #include <sched.h>
243cab2bb3Spatrick #include <stdlib.h>
253cab2bb3Spatrick 
263cab2bb3Spatrick #include <algorithm>
273cab2bb3Spatrick #include <vector>
283cab2bb3Spatrick 
293cab2bb3Spatrick namespace __sanitizer {
303cab2bb3Spatrick 
313cab2bb3Spatrick struct TidReporterArgument {
TidReporterArgument__sanitizer::TidReporterArgument323cab2bb3Spatrick   TidReporterArgument() {
333cab2bb3Spatrick     pthread_mutex_init(&terminate_thread_mutex, NULL);
343cab2bb3Spatrick     pthread_mutex_init(&tid_reported_mutex, NULL);
353cab2bb3Spatrick     pthread_cond_init(&terminate_thread_cond, NULL);
363cab2bb3Spatrick     pthread_cond_init(&tid_reported_cond, NULL);
373cab2bb3Spatrick     terminate_thread = false;
383cab2bb3Spatrick   }
393cab2bb3Spatrick 
~TidReporterArgument__sanitizer::TidReporterArgument403cab2bb3Spatrick   ~TidReporterArgument() {
413cab2bb3Spatrick     pthread_mutex_destroy(&terminate_thread_mutex);
423cab2bb3Spatrick     pthread_mutex_destroy(&tid_reported_mutex);
433cab2bb3Spatrick     pthread_cond_destroy(&terminate_thread_cond);
443cab2bb3Spatrick     pthread_cond_destroy(&tid_reported_cond);
453cab2bb3Spatrick   }
463cab2bb3Spatrick 
473cab2bb3Spatrick   tid_t reported_tid;
483cab2bb3Spatrick   // For signaling to spawned threads that they should terminate.
493cab2bb3Spatrick   pthread_cond_t terminate_thread_cond;
503cab2bb3Spatrick   pthread_mutex_t terminate_thread_mutex;
513cab2bb3Spatrick   bool terminate_thread;
523cab2bb3Spatrick   // For signaling to main thread that a child thread has reported its tid.
533cab2bb3Spatrick   pthread_cond_t tid_reported_cond;
543cab2bb3Spatrick   pthread_mutex_t tid_reported_mutex;
553cab2bb3Spatrick 
563cab2bb3Spatrick  private:
573cab2bb3Spatrick   // Disallow evil constructors
583cab2bb3Spatrick   TidReporterArgument(const TidReporterArgument &);
593cab2bb3Spatrick   void operator=(const TidReporterArgument &);
603cab2bb3Spatrick };
613cab2bb3Spatrick 
623cab2bb3Spatrick class ThreadListerTest : public ::testing::Test {
633cab2bb3Spatrick  protected:
SetUp()643cab2bb3Spatrick   virtual void SetUp() {
653cab2bb3Spatrick     pthread_t pthread_id;
663cab2bb3Spatrick     tid_t tid;
673cab2bb3Spatrick     for (uptr i = 0; i < kThreadCount; i++) {
683cab2bb3Spatrick       SpawnTidReporter(&pthread_id, &tid);
693cab2bb3Spatrick       pthread_ids_.push_back(pthread_id);
703cab2bb3Spatrick       tids_.push_back(tid);
713cab2bb3Spatrick     }
723cab2bb3Spatrick   }
733cab2bb3Spatrick 
TearDown()743cab2bb3Spatrick   virtual void TearDown() {
753cab2bb3Spatrick     pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
763cab2bb3Spatrick     thread_arg.terminate_thread = true;
773cab2bb3Spatrick     pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
783cab2bb3Spatrick     pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
793cab2bb3Spatrick     for (uptr i = 0; i < pthread_ids_.size(); i++)
803cab2bb3Spatrick       pthread_join(pthread_ids_[i], NULL);
813cab2bb3Spatrick   }
823cab2bb3Spatrick 
833cab2bb3Spatrick   void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid);
843cab2bb3Spatrick 
853cab2bb3Spatrick   static const uptr kThreadCount = 20;
863cab2bb3Spatrick 
873cab2bb3Spatrick   std::vector<pthread_t> pthread_ids_;
883cab2bb3Spatrick   std::vector<tid_t> tids_;
893cab2bb3Spatrick 
903cab2bb3Spatrick   TidReporterArgument thread_arg;
913cab2bb3Spatrick };
923cab2bb3Spatrick 
933cab2bb3Spatrick // Writes its TID once to reported_tid and waits until signaled to terminate.
TidReporterThread(void * argument)943cab2bb3Spatrick void *TidReporterThread(void *argument) {
953cab2bb3Spatrick   TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
963cab2bb3Spatrick   pthread_mutex_lock(&arg->tid_reported_mutex);
973cab2bb3Spatrick   arg->reported_tid = GetTid();
983cab2bb3Spatrick   pthread_cond_broadcast(&arg->tid_reported_cond);
993cab2bb3Spatrick   pthread_mutex_unlock(&arg->tid_reported_mutex);
1003cab2bb3Spatrick 
1013cab2bb3Spatrick   pthread_mutex_lock(&arg->terminate_thread_mutex);
1023cab2bb3Spatrick   while (!arg->terminate_thread)
1033cab2bb3Spatrick     pthread_cond_wait(&arg->terminate_thread_cond,
1043cab2bb3Spatrick                       &arg->terminate_thread_mutex);
1053cab2bb3Spatrick   pthread_mutex_unlock(&arg->terminate_thread_mutex);
1063cab2bb3Spatrick   return NULL;
1073cab2bb3Spatrick }
1083cab2bb3Spatrick 
SpawnTidReporter(pthread_t * pthread_id,tid_t * tid)1093cab2bb3Spatrick void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) {
1103cab2bb3Spatrick   pthread_mutex_lock(&thread_arg.tid_reported_mutex);
1113cab2bb3Spatrick   thread_arg.reported_tid = -1;
1123cab2bb3Spatrick   ASSERT_EQ(0, pthread_create(pthread_id, NULL,
1133cab2bb3Spatrick                               TidReporterThread,
1143cab2bb3Spatrick                               &thread_arg));
1153cab2bb3Spatrick   while (thread_arg.reported_tid == (tid_t)(-1))
1163cab2bb3Spatrick     pthread_cond_wait(&thread_arg.tid_reported_cond,
1173cab2bb3Spatrick                       &thread_arg.tid_reported_mutex);
1183cab2bb3Spatrick   pthread_mutex_unlock(&thread_arg.tid_reported_mutex);
1193cab2bb3Spatrick   *tid = thread_arg.reported_tid;
1203cab2bb3Spatrick }
1213cab2bb3Spatrick 
ReadTidsToVector(ThreadLister * thread_lister)1223cab2bb3Spatrick static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) {
1233cab2bb3Spatrick   std::vector<tid_t> listed_tids;
1243cab2bb3Spatrick   InternalMmapVector<tid_t> threads(128);
1253cab2bb3Spatrick   EXPECT_TRUE(thread_lister->ListThreads(&threads));
1263cab2bb3Spatrick   return std::vector<tid_t>(threads.begin(), threads.end());
1273cab2bb3Spatrick }
1283cab2bb3Spatrick 
Includes(std::vector<tid_t> first,std::vector<tid_t> second)1293cab2bb3Spatrick static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {
1303cab2bb3Spatrick   std::sort(first.begin(), first.end());
1313cab2bb3Spatrick   std::sort(second.begin(), second.end());
1323cab2bb3Spatrick   return std::includes(first.begin(), first.end(),
1333cab2bb3Spatrick                        second.begin(), second.end());
1343cab2bb3Spatrick }
1353cab2bb3Spatrick 
HasElement(const std::vector<tid_t> & vector,tid_t element)1363cab2bb3Spatrick static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
1373cab2bb3Spatrick   return std::find(vector.begin(), vector.end(), element) != vector.end();
1383cab2bb3Spatrick }
1393cab2bb3Spatrick 
1403cab2bb3Spatrick // ThreadLister's output should include the current thread's TID and the TID of
1413cab2bb3Spatrick // every thread we spawned.
TEST_F(ThreadListerTest,ThreadListerSeesAllSpawnedThreads)1423cab2bb3Spatrick TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
1433cab2bb3Spatrick   tid_t self_tid = GetTid();
1443cab2bb3Spatrick   ThreadLister thread_lister(getpid());
1453cab2bb3Spatrick   std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
1463cab2bb3Spatrick   ASSERT_TRUE(HasElement(listed_tids, self_tid));
1473cab2bb3Spatrick   ASSERT_TRUE(Includes(listed_tids, tids_));
1483cab2bb3Spatrick }
1493cab2bb3Spatrick 
TEST_F(ThreadListerTest,DoNotForgetThreads)1503cab2bb3Spatrick TEST_F(ThreadListerTest, DoNotForgetThreads) {
1513cab2bb3Spatrick   ThreadLister thread_lister(getpid());
1523cab2bb3Spatrick 
1533cab2bb3Spatrick   // Run the loop body twice, because ThreadLister might behave differently if
1543cab2bb3Spatrick   // called on a freshly created object.
1553cab2bb3Spatrick   for (uptr i = 0; i < 2; i++) {
1563cab2bb3Spatrick     std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
1573cab2bb3Spatrick     ASSERT_TRUE(Includes(listed_tids, tids_));
1583cab2bb3Spatrick   }
1593cab2bb3Spatrick }
1603cab2bb3Spatrick 
1613cab2bb3Spatrick // If new threads have spawned during ThreadLister object's lifetime, calling
1623cab2bb3Spatrick // relisting should cause ThreadLister to recognize their existence.
TEST_F(ThreadListerTest,NewThreads)1633cab2bb3Spatrick TEST_F(ThreadListerTest, NewThreads) {
1643cab2bb3Spatrick   ThreadLister thread_lister(getpid());
1653cab2bb3Spatrick   std::vector<tid_t> threads_before_extra = ReadTidsToVector(&thread_lister);
1663cab2bb3Spatrick 
1673cab2bb3Spatrick   pthread_t extra_pthread_id;
1683cab2bb3Spatrick   tid_t extra_tid;
1693cab2bb3Spatrick   SpawnTidReporter(&extra_pthread_id, &extra_tid);
1703cab2bb3Spatrick   // Register the new thread so it gets terminated in TearDown().
1713cab2bb3Spatrick   pthread_ids_.push_back(extra_pthread_id);
1723cab2bb3Spatrick 
1733cab2bb3Spatrick   // It would be very bizarre if the new TID had been listed before we even
1743cab2bb3Spatrick   // spawned that thread, but it would also cause a false success in this test,
1753cab2bb3Spatrick   // so better check for that.
1763cab2bb3Spatrick   ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));
1773cab2bb3Spatrick 
1783cab2bb3Spatrick   std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
1793cab2bb3Spatrick   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
1803cab2bb3Spatrick }
1813cab2bb3Spatrick 
TEST(SanitizerCommon,SetEnvTest)1823cab2bb3Spatrick TEST(SanitizerCommon, SetEnvTest) {
1833cab2bb3Spatrick   const char kEnvName[] = "ENV_FOO";
1843cab2bb3Spatrick   SetEnv(kEnvName, "value");
1853cab2bb3Spatrick   EXPECT_STREQ("value", getenv(kEnvName));
1863cab2bb3Spatrick   unsetenv(kEnvName);
1873cab2bb3Spatrick   EXPECT_EQ(0, getenv(kEnvName));
1883cab2bb3Spatrick }
1893cab2bb3Spatrick 
1903cab2bb3Spatrick #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
1913cab2bb3Spatrick // libpthread puts the thread descriptor at the end of stack space.
thread_descriptor_size_test_func(void * arg)1923cab2bb3Spatrick void *thread_descriptor_size_test_func(void *arg) {
193*d89ec533Spatrick   uptr descr_addr = (uptr)pthread_self();
1943cab2bb3Spatrick   pthread_attr_t attr;
1953cab2bb3Spatrick   pthread_getattr_np(pthread_self(), &attr);
1963cab2bb3Spatrick   void *stackaddr;
1973cab2bb3Spatrick   size_t stacksize;
1983cab2bb3Spatrick   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
1993cab2bb3Spatrick   return (void *)((uptr)stackaddr + stacksize - descr_addr);
2003cab2bb3Spatrick }
2013cab2bb3Spatrick 
TEST(SanitizerLinux,ThreadDescriptorSize)2023cab2bb3Spatrick TEST(SanitizerLinux, ThreadDescriptorSize) {
2033cab2bb3Spatrick   pthread_t tid;
2043cab2bb3Spatrick   void *result;
2053cab2bb3Spatrick   ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
2063cab2bb3Spatrick   ASSERT_EQ(0, pthread_join(tid, &result));
2073cab2bb3Spatrick   EXPECT_EQ((uptr)result, ThreadDescriptorSize());
2083cab2bb3Spatrick }
2093cab2bb3Spatrick #endif
2103cab2bb3Spatrick 
TEST(SanitizerCommon,LibraryNameIs)2113cab2bb3Spatrick TEST(SanitizerCommon, LibraryNameIs) {
2123cab2bb3Spatrick   EXPECT_FALSE(LibraryNameIs("", ""));
2133cab2bb3Spatrick 
2143cab2bb3Spatrick   char full_name[256];
2153cab2bb3Spatrick   const char *paths[] = { "", "/", "/path/to/" };
2163cab2bb3Spatrick   const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
2173cab2bb3Spatrick   const char *base_names[] = { "lib", "lib.0", "lib-i386" };
2183cab2bb3Spatrick   const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
2193cab2bb3Spatrick   for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
2203cab2bb3Spatrick     for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
2213cab2bb3Spatrick       for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
2223cab2bb3Spatrick         internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
2233cab2bb3Spatrick                           paths[i], base_names[k], suffixes[j]);
2243cab2bb3Spatrick         EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
2253cab2bb3Spatrick             << "Full name " << full_name
2263cab2bb3Spatrick             << " doesn't match base name " << base_names[k];
2273cab2bb3Spatrick         for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
2283cab2bb3Spatrick           EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
2293cab2bb3Spatrick             << "Full name " << full_name
2303cab2bb3Spatrick             << " matches base name " << wrong_names[m];
2313cab2bb3Spatrick       }
2323cab2bb3Spatrick     }
2333cab2bb3Spatrick }
2343cab2bb3Spatrick 
2353cab2bb3Spatrick #if defined(__mips64)
2363cab2bb3Spatrick // Effectively, this is a test for ThreadDescriptorSize() which is used to
2373cab2bb3Spatrick // compute ThreadSelf().
TEST(SanitizerLinux,ThreadSelfTest)2383cab2bb3Spatrick TEST(SanitizerLinux, ThreadSelfTest) {
2393cab2bb3Spatrick   ASSERT_EQ(pthread_self(), ThreadSelf());
2403cab2bb3Spatrick }
2413cab2bb3Spatrick #endif
2423cab2bb3Spatrick 
TEST(SanitizerCommon,StartSubprocessTest)2433cab2bb3Spatrick TEST(SanitizerCommon, StartSubprocessTest) {
2443cab2bb3Spatrick   int pipe_fds[2];
2453cab2bb3Spatrick   ASSERT_EQ(0, pipe(pipe_fds));
2463cab2bb3Spatrick #if SANITIZER_ANDROID
2473cab2bb3Spatrick   const char *shell = "/system/bin/sh";
2483cab2bb3Spatrick #else
2493cab2bb3Spatrick   const char *shell = "/bin/sh";
2503cab2bb3Spatrick #endif
2513cab2bb3Spatrick   const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
2521f9cb04fSpatrick   int pid = StartSubprocess(shell, argv, GetEnviron(),
2533cab2bb3Spatrick                             /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
2543cab2bb3Spatrick   ASSERT_GT(pid, 0);
2553cab2bb3Spatrick 
2563cab2bb3Spatrick   // wait for process to finish.
2573cab2bb3Spatrick   while (IsProcessRunning(pid)) {
2583cab2bb3Spatrick   }
2593cab2bb3Spatrick   ASSERT_FALSE(IsProcessRunning(pid));
2603cab2bb3Spatrick 
2613cab2bb3Spatrick   char buffer[256];
2623cab2bb3Spatrick   {
2633cab2bb3Spatrick     char *ptr = buffer;
2643cab2bb3Spatrick     uptr bytes_read;
2653cab2bb3Spatrick     while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
2663cab2bb3Spatrick       if (!bytes_read) {
2673cab2bb3Spatrick         break;
2683cab2bb3Spatrick       }
2693cab2bb3Spatrick       ptr += bytes_read;
2703cab2bb3Spatrick     }
2713cab2bb3Spatrick     ASSERT_EQ(5, ptr - buffer);
2723cab2bb3Spatrick     *ptr = 0;
2733cab2bb3Spatrick   }
2743cab2bb3Spatrick   ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
2753cab2bb3Spatrick   internal_close(pipe_fds[0]);
2763cab2bb3Spatrick }
2773cab2bb3Spatrick 
2783cab2bb3Spatrick }  // namespace __sanitizer
2793cab2bb3Spatrick 
2803cab2bb3Spatrick #endif  // SANITIZER_LINUX
281