Home | History | Annotate | 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 "gtest/gtest.h"
     21 
     22 #include <pthread.h>
     23 #include <sched.h>
     24 #include <stdlib.h>
     25 
     26 #include <algorithm>
     27 #include <vector>
     28 
     29 namespace __sanitizer {
     30 
     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;
     38   }
     39 
     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);
     45   }
     46 
     47   pid_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;
     55 
     56  private:
     57   // Disallow evil constructors
     58   TidReporterArgument(const TidReporterArgument &);
     59   void operator=(const TidReporterArgument &);
     60 };
     61 
     62 class ThreadListerTest : public ::testing::Test {
     63  protected:
     64   virtual void SetUp() {
     65     pthread_t pthread_id;
     66     pid_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);
     71     }
     72   }
     73 
     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);
     81   }
     82 
     83   void SpawnTidReporter(pthread_t *pthread_id, pid_t *tid);
     84 
     85   static const uptr kThreadCount = 20;
     86 
     87   std::vector<pthread_t> pthread_ids_;
     88   std::vector<pid_t> tids_;
     89 
     90   TidReporterArgument thread_arg;
     91 };
     92 
     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);
    100 
    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;
    107 }
    108 
    109 void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id,
    110                                         pid_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 == -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<pid_t> ReadTidsToVector(ThreadLister *thread_lister) {
    124   std::vector<pid_t> listed_tids;
    125   pid_t tid;
    126   while ((tid = thread_lister->GetNextTID()) >= 0)
    127     listed_tids.push_back(tid);
    128   EXPECT_FALSE(thread_lister->error());
    129   return listed_tids;
    130 }
    131 
    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());
    137 }
    138 
    139 static bool HasElement(std::vector<pid_t> vector, pid_t element) {
    140   return std::find(vector.begin(), vector.end(), element) != vector.end();
    141 }
    142 
    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_));
    151 }
    152 
    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());
    157 
    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_));
    164   }
    165 }
    166 
    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);
    172 
    173   pthread_t extra_pthread_id;
    174   pid_t extra_tid;
    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);
    178 
    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));
    183 
    184   thread_lister.Reset();
    185 
    186   std::vector<pid_t> threads_after_extra = ReadTidsToVector(&thread_lister);
    187   ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));
    188 }
    189 
    190 TEST(SanitizerCommon, SetEnvTest) {
    191   const char kEnvName[] = "ENV_FOO";
    192   SetEnv(kEnvName, "value");
    193   EXPECT_STREQ("value", getenv(kEnvName));
    194   unsetenv(kEnvName);
    195   EXPECT_EQ(0, getenv(kEnvName));
    196 }
    197 
    198 #if defined(__x86_64__) || defined(__i386__)
    199 void *thread_self_offset_test_func(void *arg) {
    200   bool result =
    201       *(uptr *)((char *)ThreadSelf() + ThreadSelfOffset()) == ThreadSelf();
    202   return (void *)result;
    203 }
    204 
    205 TEST(SanitizerLinux, ThreadSelfOffset) {
    206   EXPECT_TRUE((bool)thread_self_offset_test_func(0));
    207   pthread_t tid;
    208   void *result;
    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);
    212 }
    213 
    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();
    217   pthread_attr_t attr;
    218   pthread_getattr_np(pthread_self(), &attr);
    219   void *stackaddr;
    220   size_t stacksize;
    221   pthread_attr_getstack(&attr, &stackaddr, &stacksize);
    222   return (void *)((uptr)stackaddr + stacksize - descr_addr);
    223 }
    224 
    225 TEST(SanitizerLinux, ThreadDescriptorSize) {
    226   pthread_t tid;
    227   void *result;
    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());
    231 }
    232 #endif
    233 
    234 TEST(SanitizerCommon, LibraryNameIs) {
    235   EXPECT_FALSE(LibraryNameIs("", ""));
    236 
    237   char full_name[256];
    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];
    254       }
    255     }
    256 }
    257 
    258 }  // namespace __sanitizer
    259 
    260 #endif  // SANITIZER_LINUX
    261