brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.4 KiB · bcfa31d Raw
284 lines · cpp
1//===-- sanitizer_linux_test.cpp ------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8//9// Tests for sanitizer_linux.h10//11//===----------------------------------------------------------------------===//12 13#include "sanitizer_common/sanitizer_platform.h"14#if SANITIZER_LINUX15 16#  include <pthread.h>17#  include <sched.h>18#  include <stdlib.h>19 20#  include <algorithm>21#  include <vector>22 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"27 28namespace __sanitizer {29 30struct 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;37  }38 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);44  }45 46  ThreadID reported_tid;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;54 55 private:56  // Disallow evil constructors57  TidReporterArgument(const TidReporterArgument &);58  void operator=(const TidReporterArgument &);59};60 61class ThreadListerTest : public ::testing::Test {62 protected:63  virtual void SetUp() {64    pthread_t pthread_id;65    ThreadID tid;66    for (uptr i = 0; i < kThreadCount; i++) {67      SpawnTidReporter(&pthread_id, &tid);68      pthread_ids_.push_back(pthread_id);69      tids_.push_back(tid);70    }71  }72 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);80  }81 82  void SpawnTidReporter(pthread_t *pthread_id, ThreadID *tid);83 84  static const uptr kThreadCount = 20;85 86  std::vector<pthread_t> pthread_ids_;87  std::vector<ThreadID> tids_;88 89  TidReporterArgument thread_arg;90};91 92// Writes its TID once to reported_tid and waits until signaled to terminate.93void *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);99 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);105  return NULL;106}107 108void ThreadListerTest::SpawnTidReporter(pthread_t *pthread_id, ThreadID *tid) {109  pthread_mutex_lock(&thread_arg.tid_reported_mutex);110  thread_arg.reported_tid = -1;111  ASSERT_EQ(0,112            pthread_create(pthread_id, NULL, TidReporterThread, &thread_arg));113  while (thread_arg.reported_tid == (ThreadID)(-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;118}119 120static std::vector<ThreadID> ReadTidsToVector(ThreadLister *thread_lister) {121  std::vector<ThreadID> listed_tids;122  InternalMmapVector<ThreadID> threads(128);123  EXPECT_TRUE(thread_lister->ListThreads(&threads));124  return std::vector<ThreadID>(threads.begin(), threads.end());125}126 127static bool Includes(std::vector<ThreadID> first,128                     std::vector<ThreadID> second) {129  std::sort(first.begin(), first.end());130  std::sort(second.begin(), second.end());131  return std::includes(first.begin(), first.end(), second.begin(),132                       second.end());133}134 135static bool HasElement(const std::vector<ThreadID> &vector, ThreadID element) {136  return std::find(vector.begin(), vector.end(), element) != vector.end();137}138 139// ThreadLister's output should include the current thread's TID and the TID of140// every thread we spawned.141TEST_F(ThreadListerTest, ThreadListerSeesAllSpawnedThreads) {142  ThreadID self_tid = GetTid();143  ThreadLister thread_lister(getpid());144  std::vector<ThreadID> listed_tids = ReadTidsToVector(&thread_lister);145  ASSERT_TRUE(HasElement(listed_tids, self_tid));146  ASSERT_TRUE(Includes(listed_tids, tids_));147 148  ASSERT_NE(nullptr, thread_lister.LoadStatus(self_tid));149  for (auto tid : tids_) ASSERT_NE(nullptr, thread_lister.LoadStatus(tid));150}151 152TEST_F(ThreadListerTest, DoNotForgetThreads) {153  ThreadLister thread_lister(getpid());154 155  // Run the loop body twice, because ThreadLister might behave differently if156  // called on a freshly created object.157  for (uptr i = 0; i < 2; i++) {158    std::vector<ThreadID> listed_tids = ReadTidsToVector(&thread_lister);159    ASSERT_TRUE(Includes(listed_tids, tids_));160  }161}162 163// If new threads have spawned during ThreadLister object's lifetime, calling164// relisting should cause ThreadLister to recognize their existence.165TEST_F(ThreadListerTest, NewThreads) {166  ThreadLister thread_lister(getpid());167  std::vector<ThreadID> threads_before_extra = ReadTidsToVector(&thread_lister);168 169  pthread_t extra_pthread_id;170  ThreadID extra_tid;171  SpawnTidReporter(&extra_pthread_id, &extra_tid);172  // Register the new thread so it gets terminated in TearDown().173  pthread_ids_.push_back(extra_pthread_id);174 175  // It would be very bizarre if the new TID had been listed before we even176  // spawned that thread, but it would also cause a false success in this test,177  // so better check for that.178  ASSERT_FALSE(HasElement(threads_before_extra, extra_tid));179 180  std::vector<ThreadID> threads_after_extra = ReadTidsToVector(&thread_lister);181  ASSERT_TRUE(HasElement(threads_after_extra, extra_tid));182}183 184TEST(SanitizerCommon, SetEnvTest) {185  const char kEnvName[] = "ENV_FOO";186  SetEnv(kEnvName, "value");187  EXPECT_STREQ("value", getenv(kEnvName));188  unsetenv(kEnvName);189  EXPECT_EQ(0, getenv(kEnvName));190}191 192#  if (defined(__x86_64__) || defined(__i386__)) && !SANITIZER_ANDROID193// libpthread puts the thread descriptor at the end of stack space.194void *thread_descriptor_size_test_func(void *arg) {195  uptr descr_addr = (uptr)pthread_self();196  pthread_attr_t attr;197  pthread_getattr_np(pthread_self(), &attr);198  void *stackaddr;199  size_t stacksize;200  pthread_attr_getstack(&attr, &stackaddr, &stacksize);201  return (void *)((uptr)stackaddr + stacksize - descr_addr);202}203 204TEST(SanitizerLinux, ThreadDescriptorSize) {205  pthread_t tid;206  void *result;207  ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));208  ASSERT_EQ(0, pthread_join(tid, &result));209  InitTlsSize();210  EXPECT_EQ((uptr)result, ThreadDescriptorSize());211}212#  endif213 214TEST(SanitizerCommon, LibraryNameIs) {215  EXPECT_FALSE(LibraryNameIs("", ""));216 217  char full_name[256];218  const char *paths[] = {"", "/", "/path/to/"};219  const char *suffixes[] = {"", "-linux", ".1.2", "-linux.1.2"};220  const char *base_names[] = {"lib", "lib.0", "lib-i386"};221  const char *wrong_names[] = {"", "lib.9", "lib-x86_64"};222  for (uptr i = 0; i < ARRAY_SIZE(paths); i++)223    for (uptr j = 0; j < ARRAY_SIZE(suffixes); j++) {224      for (uptr k = 0; k < ARRAY_SIZE(base_names); k++) {225        internal_snprintf(full_name, ARRAY_SIZE(full_name), "%s%s%s.so",226                          paths[i], base_names[k], suffixes[j]);227        EXPECT_TRUE(LibraryNameIs(full_name, base_names[k]))228            << "Full name " << full_name << " doesn't match base name "229            << base_names[k];230        for (uptr m = 0; m < ARRAY_SIZE(wrong_names); m++)231          EXPECT_FALSE(LibraryNameIs(full_name, wrong_names[m]))232              << "Full name " << full_name << " matches base name "233              << wrong_names[m];234      }235    }236}237 238#  if defined(__mips64)239// Effectively, this is a test for ThreadDescriptorSize() which is used to240// compute ThreadSelf().241TEST(SanitizerLinux, ThreadSelfTest) {242  ASSERT_EQ(pthread_self(), ThreadSelf());243}244#  endif245 246TEST(SanitizerCommon, StartSubprocessTest) {247  int pipe_fds[2];248  ASSERT_EQ(0, pipe(pipe_fds));249#  if SANITIZER_ANDROID250  const char *shell = "/system/bin/sh";251#  else252  const char *shell = "/bin/sh";253#  endif254  const char *argv[] = {shell, "-c", "echo -n 'hello'", (char *)NULL};255  int pid = StartSubprocess(shell, argv, GetEnviron(),256                            /* stdin */ kInvalidFd, /* stdout */ pipe_fds[1]);257  ASSERT_GT(pid, 0);258 259  // wait for process to finish.260  while (IsProcessRunning(pid)) {261  }262  ASSERT_FALSE(IsProcessRunning(pid));263 264  char buffer[256];265  {266    char *ptr = buffer;267    uptr bytes_read;268    while (ReadFromFile(pipe_fds[0], ptr, 256, &bytes_read)) {269      if (!bytes_read) {270        break;271      }272      ptr += bytes_read;273    }274    ASSERT_EQ(5, ptr - buffer);275    *ptr = 0;276  }277  ASSERT_EQ(0, strcmp(buffer, "hello")) << "Buffer: " << buffer;278  internal_close(pipe_fds[0]);279}280 281}  // namespace __sanitizer282 283#endif  // SANITIZER_LINUX284