1 // Regression test for a deadlock in leak detection,
2 // where lsan would call dl_iterate_phdr while holding the allocator lock.
3 // RUN: %clangxx_lsan %s -o %t && %run %t
4
5 #include <link.h>
6 #include <mutex>
7 #include <stdlib.h>
8 #include <thread>
9 #include <unistd.h>
10
11 std::mutex in, out;
12
Callback(struct dl_phdr_info * info,size_t size,void * data)13 int Callback(struct dl_phdr_info *info, size_t size, void *data) {
14 for (int step = 0; step < 50; ++step) {
15 void *p[1000];
16 for (int i = 0; i < 1000; ++i)
17 p[i] = malloc(10 * i);
18
19 if (step == 0)
20 in.unlock();
21
22 for (int i = 0; i < 1000; ++i)
23 free(p[i]);
24 }
25 out.unlock();
26 return 1; // just once
27 }
28
Watchdog()29 void Watchdog() {
30 // This is just a fail-safe to turn a deadlock (in case the bug reappears)
31 // into a (slow) test failure.
32 usleep(20000000);
33 if (!out.try_lock()) {
34 write(2, "DEADLOCK\n", 9);
35 exit(1);
36 }
37 }
38
main()39 int main() {
40 in.lock();
41 out.lock();
42
43 std::thread t([] { dl_iterate_phdr(Callback, nullptr); });
44 t.detach();
45
46 std::thread w(Watchdog);
47 w.detach();
48
49 // Wait for the malloc thread to preheat, then start leak detection (on exit)
50 in.lock();
51 return 0;
52 }
53