blob: 4bc4c94c7425983e7642e041396ddb98d9f4ffe1 [file] [edit]
// RUN: %clang_analyze_cc1 -verify %s \
// RUN: -analyzer-checker=core,unix.BlockInCriticalSection
void sleep(int x);
namespace std {
struct mutex {
void lock();
void unlock();
};
// libc++-shaped unique_lock: ctor and dtor have non-empty bodies that call
// the underlying mutex's lock()/unlock() member functions.
template <class M>
struct unique_lock {
M *m_;
bool owns_;
explicit unique_lock(M &m) : m_(&m), owns_(true) { m_->lock(); }
~unique_lock() {
if (owns_)
m_->unlock();
}
};
} // namespace std
// Recursive use of the RAII guard. Without the fix, deep recursion would
// prevent the dtor body from inlining at the inlining-stack-depth limit;
// the inner mutex unlock would not fire, used to emit a leak FP.
struct C {
std::mutex m;
bool aborted;
bool getAborted() {
std::unique_lock<std::mutex> lk(m);
return aborted;
}
void recurse() {
if (getAborted())
recurse();
sleep(1); // no-warning
}
};
// Direct case: RAII guard scoped to a function body. Constructor inlining +
// destructor inlining must not double-count, even when both bodies inline.
void callee(std::mutex &m) {
std::unique_lock<std::mutex> lk(m);
// The lock IS held here so blocking is correctly diagnosed.
sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
} // dtor fires here, releases the lock; no further sleep should warn.
void top(std::mutex &m) {
callee(m);
sleep(1); // no-warning: the lock from `callee` was released by ~unique_lock before this sleep.
}