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
11std::mutex in, out;
12
13int 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(size: 10 * i);
18
19 if (step == 0)
20 in.unlock();
21
22 for (int i = 0; i < 1000; ++i)
23 free(ptr: p[i]);
24 }
25 out.unlock();
26 return 1; // just once
27}
28
29void 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(useconds: 40000000);
33 if (!out.try_lock()) {
34 write(fd: 2, buf: "DEADLOCK\n", n: 9);
35 exit(status: 1);
36 }
37}
38
39int main() {
40 in.lock();
41 out.lock();
42
43 std::thread t([] { dl_iterate_phdr(callback: Callback, data: 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

source code of compiler-rt/test/lsan/TestCases/Linux/libdl_deadlock.cpp