brintos

brintos / llvm-project-archived public Read only

0
0
Text · 3.8 KiB · 2e28a23 Raw
113 lines · c
1// Test that dyld interposition works in the presence of DYLD_INSERT_LIBRARIES.2// Additionally, the injected library also has a pthread introspection hook that3// calls intercepted APIs before and after calling through to the TSan hook.4// This mirrors what libBacktraceRecording.dylib (Xcode 'Queue Debugging'5// feature) does.6 7// RUN: %clang_tsan %s -o %t8// RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB9//10// RUN: env DYLD_INSERT_LIBRARIES=%t.dylib %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'11//12// XFAIL: ios13 14#include <assert.h>15#include <pthread.h>16#include <stdio.h>17#include <string.h>18 19#if defined(SHARED_LIB)20enum {21  PTHREAD_INTROSPECTION_THREAD_CREATE = 1,22  PTHREAD_INTROSPECTION_THREAD_START,23  PTHREAD_INTROSPECTION_THREAD_TERMINATE,24  PTHREAD_INTROSPECTION_THREAD_DESTROY,25};26typedef void (*pthread_introspection_hook_t)(unsigned int event,27                                             pthread_t thread, void *addr,28                                             size_t size);29extern pthread_introspection_hook_t pthread_introspection_hook_install(30    pthread_introspection_hook_t hook);31 32static pthread_introspection_hook_t previous_pthread_hook;33static void pthread_introspection_hook(unsigned int event, pthread_t thread, void *addr, size_t size) {34  pthread_t self;35  const unsigned k_max_thread_name_size = 64;36  char name[k_max_thread_name_size];37 38  // Use some intercepted APIs *before* TSan hook runs.39  {40    self = pthread_self();41    pthread_getname_np(self, name, k_max_thread_name_size);42    if (strlen(name) == 0) {43      strlcpy(name, "n/a", 4);44    }45  }46 47  // This calls through to the TSan-installed hook, because the injected library48  // constructor (see __library_initializer() below) runs after the TSan49  // initializer.  It replaces and forward to the previously-installed TSan50  // introspection hook (very similar to what libBacktraceRecording.dylib does).51  assert(previous_pthread_hook);52  previous_pthread_hook(event, thread, addr, size);53 54  // Use some intercepted APIs *after* TSan hook runs.55  {56    assert(self == pthread_self());57    char name2[k_max_thread_name_size];58    pthread_getname_np(self, name2, k_max_thread_name_size);59    if (strlen(name2) == 0) {60      strlcpy(name2, "n/a", 4);61    }62    assert(strcmp(name, name2) == 0);63  }64 65  switch (event) {66  case PTHREAD_INTROSPECTION_THREAD_CREATE:67    fprintf(stderr, "THREAD_CREATE    %p, self: %p, name: %s\n", thread, self, name);68    break;69  case PTHREAD_INTROSPECTION_THREAD_START:70    fprintf(stderr, "THREAD_START     %p, self: %p, name: %s\n", thread, self, name);71    break;72  case PTHREAD_INTROSPECTION_THREAD_TERMINATE:73    fprintf(stderr, "THREAD_TERMINATE %p, self: %p, name: %s\n", thread, self, name);74    break;75  case PTHREAD_INTROSPECTION_THREAD_DESTROY:76    fprintf(stderr, "THREAD_DESTROY   %p, self: %p, name: %s\n", thread, self, name);77    break;78  }79}80 81__attribute__((constructor))82static void __library_initializer(void) {83  fprintf(stderr, "__library_initializer\n");84  previous_pthread_hook = pthread_introspection_hook_install(pthread_introspection_hook);85}86 87#else  // defined(SHARED_LIB)88 89void *Thread(void *a) {90  pthread_setname_np("child thread");91  fprintf(stderr, "Hello from pthread\n");92  return NULL;93}94 95int main() {96  fprintf(stderr, "main\n");97  pthread_t t;98  pthread_create(&t, NULL, Thread, NULL);99  pthread_join(t, NULL);100  fprintf(stderr, "Done.\n");101}102#endif  // defined(SHARED_LIB)103 104// CHECK: __library_initializer105// CHECK: main106// Ignore TSan background thread.107// CHECK: THREAD_CREATE108// CHECK: THREAD_CREATE    [[CHILD:0x[0-9a-f]+]]109// CHECK: THREAD_START     [[CHILD]], self: [[CHILD]], name: n/a110// CHECK: Hello from pthread111// CHECK: THREAD_TERMINATE [[CHILD]], self: [[CHILD]], name: child thread112// CHECK: THREAD_DESTROY   [[CHILD]]113