File: dyld-insert-libraries.c

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (112 lines) | stat: -rw-r--r-- 3,853 bytes parent folder | download | duplicates (20)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Test that dyld interposition works in the presence of DYLD_INSERT_LIBRARIES.
// Additionally, the injected library also has a pthread introspection hook that
// calls intercepted APIs before and after calling through to the TSan hook.
// This mirrors what libBacktraceRecording.dylib (Xcode 'Queue Debugging'
// feature) does.

// RUN: %clang_tsan %s -o %t
// RUN: %clang_tsan %s -o %t.dylib -fno-sanitize=thread -dynamiclib -DSHARED_LIB
//
// RUN: env DYLD_INSERT_LIBRARIES=%t.dylib %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer'
//
// XFAIL: ios

#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>

#if defined(SHARED_LIB)
enum {
  PTHREAD_INTROSPECTION_THREAD_CREATE = 1,
  PTHREAD_INTROSPECTION_THREAD_START,
  PTHREAD_INTROSPECTION_THREAD_TERMINATE,
  PTHREAD_INTROSPECTION_THREAD_DESTROY,
};
typedef void (*pthread_introspection_hook_t)(unsigned int event,
                                             pthread_t thread, void *addr,
                                             size_t size);
extern pthread_introspection_hook_t pthread_introspection_hook_install(
    pthread_introspection_hook_t hook);

static pthread_introspection_hook_t previous_pthread_hook;
static void pthread_introspection_hook(unsigned int event, pthread_t thread, void *addr, size_t size) {
  pthread_t self;
  const unsigned k_max_thread_name_size = 64;
  char name[k_max_thread_name_size];

  // Use some intercepted APIs *before* TSan hook runs.
  {
    self = pthread_self();
    pthread_getname_np(self, name, k_max_thread_name_size);
    if (strlen(name) == 0) {
      strlcpy(name, "n/a", 4);
    }
  }

  // This calls through to the TSan-installed hook, because the injected library
  // constructor (see __library_initializer() below) runs after the TSan
  // initializer.  It replaces and forward to the previously-installed TSan
  // introspection hook (very similar to what libBacktraceRecording.dylib does).
  assert(previous_pthread_hook);
  previous_pthread_hook(event, thread, addr, size);

  // Use some intercepted APIs *after* TSan hook runs.
  {
    assert(self == pthread_self());
    char name2[k_max_thread_name_size];
    pthread_getname_np(self, name2, k_max_thread_name_size);
    if (strlen(name2) == 0) {
      strlcpy(name2, "n/a", 4);
    }
    assert(strcmp(name, name2) == 0);
  }

  switch (event) {
  case PTHREAD_INTROSPECTION_THREAD_CREATE:
    fprintf(stderr, "THREAD_CREATE    %p, self: %p, name: %s\n", thread, self, name);
    break;
  case PTHREAD_INTROSPECTION_THREAD_START:
    fprintf(stderr, "THREAD_START     %p, self: %p, name: %s\n", thread, self, name);
    break;
  case PTHREAD_INTROSPECTION_THREAD_TERMINATE:
    fprintf(stderr, "THREAD_TERMINATE %p, self: %p, name: %s\n", thread, self, name);
    break;
  case PTHREAD_INTROSPECTION_THREAD_DESTROY:
    fprintf(stderr, "THREAD_DESTROY   %p, self: %p, name: %s\n", thread, self, name);
    break;
  }
}

__attribute__((constructor))
static void __library_initializer(void) {
  fprintf(stderr, "__library_initializer\n");
  previous_pthread_hook = pthread_introspection_hook_install(pthread_introspection_hook);
}

#else  // defined(SHARED_LIB)

void *Thread(void *a) {
  pthread_setname_np("child thread");
  fprintf(stderr, "Hello from pthread\n");
  return NULL;
}

int main() {
  fprintf(stderr, "main\n");
  pthread_t t;
  pthread_create(&t, NULL, Thread, NULL);
  pthread_join(t, NULL);
  fprintf(stderr, "Done.\n");
}
#endif  // defined(SHARED_LIB)

// CHECK: __library_initializer
// CHECK: main
// Ignore TSan background thread.
// CHECK: THREAD_CREATE
// CHECK: THREAD_CREATE    [[CHILD:0x[0-9a-f]+]]
// CHECK: THREAD_START     [[CHILD]], self: [[CHILD]], name: n/a
// CHECK: Hello from pthread
// CHECK: THREAD_TERMINATE [[CHILD]], self: [[CHILD]], name: child thread
// CHECK: THREAD_DESTROY   [[CHILD]]