// Regression test for a deadlock in leak detection,
// where lsan would call dl_iterate_phdr while holding the allocator lock.
// RUN: %clangxx_lsan %s -o %t && %run %t
#include <link.h>
#include <mutex>
#include <stdlib.h>
#include <thread>
#include <unistd.h>
std::mutex in, out;
int Callback(struct dl_phdr_info *info, size_t size, void *data) {
for (int step = 0; step < 50; ++step) {
void *p[1000];
for (int i = 0; i < 1000; ++i)
p[i] = malloc(10 * i);
if (step == 0)
in.unlock();
for (int i = 0; i < 1000; ++i)
free(p[i]);
}
out.unlock();
return 1; // just once
}
void Watchdog() {
// This is just a fail-safe to turn a deadlock (in case the bug reappears)
// into a (slow) test failure.
usleep(40000000);
if (!out.try_lock()) {
write(2, "DEADLOCK\n", 9);
exit(1);
}
}
int main() {
in.lock();
out.lock();
std::thread t([] { dl_iterate_phdr(Callback, nullptr); });
t.detach();
std::thread w(Watchdog);
w.detach();
// Wait for the malloc thread to preheat, then start leak detection (on exit)
in.lock();
return 0;
}