mirror of
https://github.com/intel/llvm.git
synced 2026-01-17 23:45:25 +08:00
Fix ASAN failure in TestSingleThreadStepTimeout.py (#102208)
This PR fixes the ASAN failure in https://github.com/llvm/llvm-project/pull/90930. The original PR made the assumption that parent `ThreadPlanStepOverRange`'s lifetime will always be longer than `ThreadPlanSingleThreadTimeout` leaf plan so it passes the `m_timeout_info` as reference to it. From the ASAN failure, it seems that this assumption may not be true (likely the thread stack is holding a strong reference to the leaf plan). This PR fixes this lifetime issue by using shared pointer instead of passing by reference. --------- Co-authored-by: jeffreytan81 <jeffreytan@fb.com>
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class ThreadPlanSingleThreadTimeout;
|
||||
//
|
||||
// Thread plan used by single thread execution to issue timeout. This is useful
|
||||
// to detect potential deadlock in single thread execution. The timeout measures
|
||||
@@ -46,6 +47,8 @@ public:
|
||||
bool m_isAlive = false;
|
||||
ThreadPlanSingleThreadTimeout::State m_last_state = State::WaitTimeout;
|
||||
};
|
||||
using TimeoutInfoSP =
|
||||
std::shared_ptr<ThreadPlanSingleThreadTimeout::TimeoutInfo>;
|
||||
|
||||
~ThreadPlanSingleThreadTimeout() override;
|
||||
|
||||
@@ -54,11 +57,11 @@ public:
|
||||
// state. The reference of \param info is passed in so that when
|
||||
// ThreadPlanSingleThreadTimeout got popped its last state can be stored
|
||||
// in it for future resume.
|
||||
static void PushNewWithTimeout(Thread &thread, TimeoutInfo &info);
|
||||
static void PushNewWithTimeout(Thread &thread, TimeoutInfoSP &info);
|
||||
|
||||
// Push a new ThreadPlanSingleThreadTimeout by restoring state from
|
||||
// input \param info and resume execution.
|
||||
static void ResumeFromPrevState(Thread &thread, TimeoutInfo &info);
|
||||
static void ResumeFromPrevState(Thread &thread, TimeoutInfoSP &info);
|
||||
|
||||
void GetDescription(Stream *s, lldb::DescriptionLevel level) override;
|
||||
bool ValidatePlan(Stream *error) override { return true; }
|
||||
@@ -78,7 +81,7 @@ public:
|
||||
bool StopOthers() override;
|
||||
|
||||
private:
|
||||
ThreadPlanSingleThreadTimeout(Thread &thread, TimeoutInfo &info);
|
||||
ThreadPlanSingleThreadTimeout(Thread &thread, TimeoutInfoSP &info);
|
||||
|
||||
bool IsTimeoutAsyncInterrupt(Event *event_ptr);
|
||||
bool HandleEvent(Event *event_ptr);
|
||||
@@ -91,7 +94,7 @@ private:
|
||||
const ThreadPlanSingleThreadTimeout &
|
||||
operator=(const ThreadPlanSingleThreadTimeout &) = delete;
|
||||
|
||||
TimeoutInfo &m_info; // Reference to controlling ThreadPlan's TimeoutInfo.
|
||||
TimeoutInfoSP m_info; // Reference to controlling ThreadPlan's TimeoutInfo.
|
||||
State m_state;
|
||||
|
||||
// Lock for m_wakeup_cv and m_exit_flag between thread plan thread and timer
|
||||
|
||||
@@ -19,7 +19,10 @@ namespace lldb_private {
|
||||
// ResumeWithTimeout() during DoWillResume().
|
||||
class TimeoutResumeAll {
|
||||
public:
|
||||
TimeoutResumeAll(Thread &thread) : m_thread(thread) {}
|
||||
TimeoutResumeAll(Thread &thread)
|
||||
: m_thread(thread),
|
||||
m_timeout_info(
|
||||
std::make_shared<ThreadPlanSingleThreadTimeout::TimeoutInfo>()) {}
|
||||
|
||||
void PushNewTimeout() {
|
||||
ThreadPlanSingleThreadTimeout::PushNewWithTimeout(m_thread, m_timeout_info);
|
||||
@@ -32,7 +35,7 @@ public:
|
||||
|
||||
private:
|
||||
Thread &m_thread;
|
||||
ThreadPlanSingleThreadTimeout::TimeoutInfo m_timeout_info;
|
||||
ThreadPlanSingleThreadTimeout::TimeoutInfoSP m_timeout_info;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
@@ -24,19 +24,19 @@
|
||||
using namespace lldb_private;
|
||||
using namespace lldb;
|
||||
|
||||
ThreadPlanSingleThreadTimeout::ThreadPlanSingleThreadTimeout(Thread &thread,
|
||||
TimeoutInfo &info)
|
||||
ThreadPlanSingleThreadTimeout::ThreadPlanSingleThreadTimeout(
|
||||
Thread &thread, TimeoutInfoSP &info)
|
||||
: ThreadPlan(ThreadPlan::eKindSingleThreadTimeout, "Single thread timeout",
|
||||
thread, eVoteNo, eVoteNoOpinion),
|
||||
m_info(info), m_state(State::WaitTimeout) {
|
||||
// TODO: reuse m_timer_thread without recreation.
|
||||
m_timer_thread = std::thread(TimeoutThreadFunc, this);
|
||||
m_info.m_isAlive = true;
|
||||
m_state = m_info.m_last_state;
|
||||
m_info->m_isAlive = true;
|
||||
m_state = m_info->m_last_state;
|
||||
}
|
||||
|
||||
ThreadPlanSingleThreadTimeout::~ThreadPlanSingleThreadTimeout() {
|
||||
m_info.m_isAlive = false;
|
||||
m_info->m_isAlive = false;
|
||||
}
|
||||
|
||||
uint64_t ThreadPlanSingleThreadTimeout::GetRemainingTimeoutMilliSeconds() {
|
||||
@@ -66,7 +66,7 @@ std::string ThreadPlanSingleThreadTimeout::StateToString(State state) {
|
||||
}
|
||||
|
||||
void ThreadPlanSingleThreadTimeout::PushNewWithTimeout(Thread &thread,
|
||||
TimeoutInfo &info) {
|
||||
TimeoutInfoSP &info) {
|
||||
uint64_t timeout_in_ms = thread.GetSingleThreadPlanTimeout();
|
||||
if (timeout_in_ms == 0)
|
||||
return;
|
||||
@@ -88,13 +88,13 @@ void ThreadPlanSingleThreadTimeout::PushNewWithTimeout(Thread &thread,
|
||||
}
|
||||
|
||||
void ThreadPlanSingleThreadTimeout::ResumeFromPrevState(Thread &thread,
|
||||
TimeoutInfo &info) {
|
||||
TimeoutInfoSP &info) {
|
||||
uint64_t timeout_in_ms = thread.GetSingleThreadPlanTimeout();
|
||||
if (timeout_in_ms == 0)
|
||||
return;
|
||||
|
||||
// There is already an instance alive.
|
||||
if (info.m_isAlive)
|
||||
if (info->m_isAlive)
|
||||
return;
|
||||
|
||||
// Do not create timeout if we are not stopping other threads.
|
||||
@@ -118,7 +118,7 @@ bool ThreadPlanSingleThreadTimeout::WillStop() {
|
||||
LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::WillStop().");
|
||||
|
||||
// Reset the state during stop.
|
||||
m_info.m_last_state = State::WaitTimeout;
|
||||
m_info->m_last_state = State::WaitTimeout;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ void ThreadPlanSingleThreadTimeout::DidPop() {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
LLDB_LOGF(log, "ThreadPlanSingleThreadTimeout::DidPop().");
|
||||
// Tell timer thread to exit.
|
||||
m_info.m_isAlive = false;
|
||||
m_info->m_isAlive = false;
|
||||
}
|
||||
m_wakeup_cv.notify_one();
|
||||
// Wait for timer thread to exit.
|
||||
@@ -163,12 +163,12 @@ void ThreadPlanSingleThreadTimeout::TimeoutThreadFunc(
|
||||
" ms",
|
||||
timeout_in_ms);
|
||||
self->m_wakeup_cv.wait_for(lock, std::chrono::milliseconds(timeout_in_ms),
|
||||
[self] { return !self->m_info.m_isAlive; });
|
||||
[self] { return !self->m_info->m_isAlive; });
|
||||
LLDB_LOGF(log,
|
||||
"ThreadPlanSingleThreadTimeout::TimeoutThreadFunc() wake up with "
|
||||
"m_isAlive(%d).",
|
||||
self->m_info.m_isAlive);
|
||||
if (!self->m_info.m_isAlive)
|
||||
self->m_info->m_isAlive);
|
||||
if (!self->m_info->m_isAlive)
|
||||
return;
|
||||
|
||||
self->HandleTimeout();
|
||||
|
||||
Reference in New Issue
Block a user