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