Home | History | Annotate | Line # | Download | only in tests
      1 //===-- sanitizer_linux_test.cc -------------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // Tests for sanitizer_linux.h
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_common/sanitizer_platform.h"
     15 #if SANITIZER_LINUX
     16 
     17 #include "sanitizer_common/sanitizer_linux.h"
     18 
     19 #include "sanitizer_common/sanitizer_common.h"
     20 #include "sanitizer_common/sanitizer_file.h"
     21 #include "gtest/gtest.h"
     22 
     23 #include <pthread.h>
     24 #include <sched.h>
     25 #include <stdlib.h>
     26 
     27 #include <algorithm>
     28 #include <vector>
     29 
     30 namespace __sanitizer {
     31 
     32 struct TidReporterArgument {
     33   TidReporterArgument() {
     34     pthread_mutex_init(&terminate_thread_mutex, NULL);
     35     pthread_mutex_init(&tid_reported_mutex, NULL);
     36     pthread_cond_init(&terminate_thread_cond, NULL);
     37     pthread_cond_init(&tid_reported_cond, NULL);
     38     terminate_thread = false;
     39   }
     40 
     41   ~TidReporterArgument() {
     42     pthread_mutex_destroy(&terminate_thread_mutex);
     43     pthread_mutex_destroy(&tid_reported_mutex);
     44     pthread_cond_destroy(&terminate_thread_cond);
     45     pthread_cond_destroy(&tid_reported_cond);
     46   }
     47 
     48   tid_t reported_tid;
     49   // For signaling to spawned threads that they should terminate.
     50   pthread_cond_t terminate_thread_cond;
     51   pthread_mutex_t terminate_thread_mutex;
     52   bool terminate_thread;
     53   // For signaling to main thread that a child thread has reported its tid.
     54   pthread_cond_t tid_reported_cond;
     55   pthread_mutex_t tid_reported_mutex;
     56 
     57  private:
     58   // Disallow evil constructors
     59   TidReporterArgument(const TidReporterArgument &);
     60   void operator=(const TidReporterArgument &);
     61 };
     62 
     63 class ThreadListerTest : public ::testing::Test {
     64  protected:
     65   virtual void SetUp() {
     66     pthread_t pthread_id;
     67     tid_t tid;
     68     for (uptr i = 0; i < kThreadCount; i++) {
     69       SpawnTidReporter(&pthread_id, &tid);
     70       pthread_ids_.push_back(pthread_id);
     71       tids_.push_back(tid);
     72     }
     73   }
     74 
     75   virtual void TearDown() {
     76     pthread_mutex_lock(&thread_arg.terminate_thread_mutex);
     77     thread_arg.terminate_thread = true;
     78     pthread_cond_broadcast(&thread_arg.terminate_thread_cond);
     79     pthread_mutex_unlock(&thread_arg.terminate_thread_mutex);
     80     for (uptr i = 0; i < pthread_ids_.size(); i++)
     81       pthread_join(pthread_ids_[i], NULL);
     82   }
     83 
     84   void SpawnTidReporter(pthread_t *pthread_id, tid_t *tid);
     85 
     86   static const uptr kThreadCount = 20;
     87 
     88   std::vector<pthread_t> pthread_ids_;
     89   std::vector<tid_t> tids_;
     90 
     91   TidReporterArgument thread_arg;
     92 };
     93 
     94 // Writes its TID once to reported_tid and waits until signaled to terminate.
     95 void *TidReporterThread(void *argument) {
     96   TidReporterArgument *arg = reinterpret_cast<TidReporterArgument *>(argument);
     97   pthread_mutex_lock(&arg->tid_reported_mutex);
     98   arg->reported_tid = GetTid();
     99   pthread_cond_broadcast(&arg->tid_reported_cond);
    100   pthread_mutex_unlock(&arg->tid_reported_mutex);
    101 
    102   pthread_mutex_lock(&arg->terminate_thread_mutex);
    103   while (!arg->terminate_thread)
    104     pthread_cond_wait(&arg->terminate_thread_cond,
    105                       &arg->terminate_thread_mutex);
    106   pthread_mutex_unlock(&arg->terminate_thread_mutex);
    107   return NULL;
    108 }
    109 
    110 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, tid_t *tid) {
    111   pthread_mutex_lock(&thread_arg.tid_reported_mutex);
    112   thread_arg.reported_tid = -1;
    113   ASSERT_EQ(0, pthread_create(pthread_id, NULL,
    114                               TidReporterThread,
    115                               &thread_arg));
    116   while (thread_arg.reported_tid == (tid_t)(-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;
    121 }
    122 
    123 static std::vector<tid_t> ReadTidsToVector(ThreadLister *thread_lister) {
    124   std::vector<tid_t> listed_tids;
    125   InternalMmapVector<tid_t> threads(128);
    126   EXPECT_TRUE(thread_lister->ListThreads(&threads));
    127   return std::vector<tid_t>(threads.begin(), threads.end());
    128 }
    129 
    130 static bool Includes(std::vector<tid_t> first, std::vector<tid_t> second) {
    131   std::sort(first.begin(), first.end());
    132   std::sort(second.begin(), second.end());
    133   return std::includes(first.begin(), first.end(),
    134                        second.begin(), second.end());
    135 }
    136 
    137 static bool HasElement(const std::vector<tid_t> &vector, tid_t element) {
    138   return std::find(vector.begin(), vector.end(), element) != vector.end();
    139 }
    140 
    141 // ThreadLister's output should include the current thread's TID and the TID of
    142 // every thread we spawned.
    143 TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {
    144   tid_t self_tid = GetTid();
    145   ThreadLister thread_lister(getpid());
    146   std::vector<tid_t> listed_tids = ReadTidsToVector(&thread_lister);
    147   ASSERT_TRUE(HasElement(listed_tids, self_tid));
    148   ASSERT_TRUE(Includes(listed_tids, tids_));
    149 }
    150 
    151 TEST_F(ThreadListerTest, DoNotForgetThreads) {
    152   ThreadLister thread_lister(getpid());
    153 
    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_));
    159   }
    160 }
    161 
    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);
    167 
    168   pthread_t extra_pthread_id;
    169   tid_t extra_tid;
    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);
    173 
    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));
    178 
    179   std::vector<tid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
    180   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
    181 }
    182 
    183 TEST(SanitizerCommon, SetEnvTest) {
    184   const char kEnvName[] = "ENV_FOO";
    185   SetEnv(kEnvName, "value");
    186   EXPECT_STREQ("value", getenv(kEnvName));
    187   unsetenv(kEnvName);
    188   EXPECT_EQ(0, getenv(kEnvName));
    189 }
    190 
    191 #if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID
    192 void *thread_self_offset_test_func(void *arg) {
    193   bool result =
    194       *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
    195   return (void *)result;
    196 }
    197 
    198 TEST(SanitizerLinux, ThreadSelfOffset) {
    199   EXPECT_TRUE((bool)thread_self_offset_test_func(0));
    200   pthread_t tid;
    201   void *result;
    202   ASSERT_EQ(0, pthread_create(&tid, 0, thread_self_offset_test_func, 0));
    203   ASSERT_EQ(0, pthread_join(tid, &result));
    204   EXPECT_TRUE((bool)result);
    205 }
    206 
    207 // libpthread puts the thread descriptor at the end of stack space.
    208 void *thread_descriptor_size_test_func(void *arg) {
    209   uptr descr_addr = ThreadSelf();
    210   pthread_attr_t attr;
    211   pthread_getattr_np(pthread_self(), &attr);
    212   void *stackaddr;
    213   size_t stacksize;
    214   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
    215   return (void *)((uptr)stackaddr + stacksize - descr_addr);
    216 }
    217 
    218 TEST(SanitizerLinux, ThreadDescriptorSize) {
    219   pthread_t tid;
    220   void *result;
    221   ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
    222   ASSERT_EQ(0, pthread_join(tid, &result));
    223   EXPECT_EQ((uptr)result, ThreadDescriptorSize());
    224 }
    225 #endif
    226 
    227 TEST(SanitizerCommon, LibraryNameIs) {
    228   EXPECT_FALSE(LibraryNameIs("", ""));
    229 
    230   char full_name[256];
    231   const char *paths[] = { "", "/", "/path/to/" };
    232   const char *suffixes[] = { "", "-linux", ".1.2", "-linux.1.2" };
    233   const char *base_names[] = { "lib", "lib.0", "lib-i386" };
    234   const char *wrong_names[] = { "", "lib.9", "lib-x86_64" };
    235   for (uptr i = 0; i < ARRAY_SIZE(paths); i++)
    236     for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {
    237       for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {
    238         internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",
    239                           paths[i], base_names[k], suffixes[j]);
    240         EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))
    241             << "Full name " << full_name
    242             << " doesn't match base name " << base_names[k];
    243         for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)
    244           EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))
    245             << "Full name " << full_name
    246             << " matches base name " << wrong_names[m];
    247       }
    248     }
    249 }
    250 
    251 #if defined(__mips64)
    252 // Effectively, this is a test for ThreadDescriptorSize() which is used to
    253 // compute ThreadSelf().
    254 TEST(SanitizerLinux, ThreadSelfTest) {
    255   ASSERT_EQ(pthread_self(), ThreadSelf());
    256 }
    257 #endif
    258 
    259 TEST(SanitizerCommon, StartSubprocessTest) {
    260   int pipe_fds[2];
    261   ASSERT_EQ(0, pipe(pipe_fds));
    262 #if SANITIZER_ANDROID
    263   const char *shell = "/system/bin/sh";
    264 #else
    265   const char *shell = "/bin/sh";
    266 #endif
    267   const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};
    268   int pid = StartSubprocess(shell, argv,
    269                             /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);
    270   ASSERT_GT(pid, 0);
    271 
    272   // wait for process to finish.
    273   while (IsProcessRunning(pid)) {
    274   }
    275   ASSERT_FALSE(IsProcessRunning(pid));
    276 
    277   char buffer[256];
    278   {
    279     char *ptr = buffer;
    280     uptr bytes_read;
    281     while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {
    282       if (!bytes_read) {
    283         break;
    284       }
    285       ptr += bytes_read;
    286     }
    287     ASSERT_EQ(5, ptr - buffer);
    288     *ptr = 0;
    289   }
    290   ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;
    291   internal_close(pipe_fds[0]);
    292 }
    293 
    294 }  // namespace __sanitizer
    295 
    296 #endif  // SANITIZER_LINUX
    297