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