forked from OSchip/llvm-project
<rdar://problem/14526890>
Fixed a crasher when using memory threads where a thread is sticking around too long and was causing problems when it didn't have a thread plan. llvm-svn: 187395
This commit is contained in:
parent
4ed04e2ee3
commit
6e10f149c4
|
@ -238,6 +238,7 @@ public:
|
|||
typedef enum
|
||||
{
|
||||
eKindGeneric,
|
||||
eKindNull,
|
||||
eKindBase,
|
||||
eKindCallFunction,
|
||||
eKindStepInstruction,
|
||||
|
@ -435,7 +436,7 @@ public:
|
|||
virtual void
|
||||
WillPop();
|
||||
|
||||
// This pushes \a plan onto the plan stack of the current plan's thread.
|
||||
// This pushes a plan onto the plan stack of the current plan's thread.
|
||||
void
|
||||
PushPlan (lldb::ThreadPlanSP &thread_plan_sp)
|
||||
{
|
||||
|
@ -600,6 +601,57 @@ private:
|
|||
DISALLOW_COPY_AND_ASSIGN(ThreadPlan);
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ThreadPlanNull:
|
||||
// Threads are assumed to always have at least one plan on the plan stack.
|
||||
// This is put on the plan stack when a thread is destroyed so that if you
|
||||
// accidentally access a thread after it is destroyed you won't crash.
|
||||
// But asking questions of the ThreadPlanNull is definitely an error.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
class ThreadPlanNull : public ThreadPlan
|
||||
{
|
||||
public:
|
||||
ThreadPlanNull (Thread &thread);
|
||||
virtual ~ThreadPlanNull ();
|
||||
|
||||
virtual void
|
||||
GetDescription (Stream *s,
|
||||
lldb::DescriptionLevel level);
|
||||
|
||||
virtual bool
|
||||
ValidatePlan (Stream *error);
|
||||
|
||||
virtual bool
|
||||
ShouldStop (Event *event_ptr);
|
||||
|
||||
virtual bool
|
||||
MischiefManaged ();
|
||||
|
||||
virtual bool
|
||||
WillStop ();
|
||||
|
||||
virtual bool
|
||||
IsBasePlan()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
OkayToDiscard ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
DoPlanExplainsStop (Event *event_ptr);
|
||||
|
||||
virtual lldb::StateType
|
||||
GetPlanRunState ();
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
|
|
|
@ -292,6 +292,13 @@ Thread::DestroyThread ()
|
|||
m_plan_stack.clear();
|
||||
m_discarded_plan_stack.clear();
|
||||
m_completed_plan_stack.clear();
|
||||
|
||||
// Push a ThreadPlanNull on the plan stack. That way we can continue assuming that the
|
||||
// plan stack is never empty, but if somebody errantly asks questions of a destroyed thread
|
||||
// without checking first whether it is destroyed, they won't crash.
|
||||
ThreadPlanSP null_plan_sp(new ThreadPlanNull (*this));
|
||||
m_plan_stack.push_back (null_plan_sp);
|
||||
|
||||
m_stop_info_sp.reset();
|
||||
m_reg_context_sp.reset();
|
||||
m_unwinder_ap.reset();
|
||||
|
@ -362,6 +369,9 @@ Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_strea
|
|||
lldb::StopInfoSP
|
||||
Thread::GetStopInfo ()
|
||||
{
|
||||
if (m_destroy_called)
|
||||
return m_stop_info_sp;
|
||||
|
||||
ThreadPlanSP plan_sp (GetCompletedPlan());
|
||||
ProcessSP process_sp (GetProcess());
|
||||
const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
|
||||
|
@ -387,6 +397,9 @@ Thread::GetStopInfo ()
|
|||
lldb::StopInfoSP
|
||||
Thread::GetPrivateStopInfo ()
|
||||
{
|
||||
if (m_destroy_called)
|
||||
return m_stop_info_sp;
|
||||
|
||||
ProcessSP process_sp (GetProcess());
|
||||
if (process_sp)
|
||||
{
|
||||
|
|
|
@ -210,3 +210,144 @@ ThreadPlan::RunState ()
|
|||
else
|
||||
return GetPlanRunState();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// ThreadPlanNull
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
ThreadPlanNull::ThreadPlanNull (Thread &thread) :
|
||||
ThreadPlan (ThreadPlan::eKindNull,
|
||||
"Null Thread Plan",
|
||||
thread,
|
||||
eVoteNoOpinion,
|
||||
eVoteNoOpinion)
|
||||
{
|
||||
}
|
||||
|
||||
ThreadPlanNull::~ThreadPlanNull ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ThreadPlanNull::GetDescription (Stream *s,
|
||||
lldb::DescriptionLevel level)
|
||||
{
|
||||
s->PutCString("Null thread plan - thread has been destroyed.");
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanNull::ValidatePlan (Stream *error)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanNull::ShouldStop (Event *event_ptr)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanNull::WillStop ()
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr)
|
||||
{
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// The null plan is never done.
|
||||
bool
|
||||
ThreadPlanNull::MischiefManaged ()
|
||||
{
|
||||
// The null plan is never done.
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
lldb::StateType
|
||||
ThreadPlanNull::GetPlanRunState ()
|
||||
{
|
||||
// Not sure what to return here. This is a dead thread.
|
||||
#ifdef LLDB_CONFIGURATION_DEBUG
|
||||
fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#else
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
|
||||
if (log)
|
||||
log->Error("%s called on thread that has been destroyed (tid = 0x%llx, ptid = 0x%llx)",
|
||||
__PRETTY_FUNCTION__,
|
||||
m_thread.GetID(),
|
||||
m_thread.GetProtocolID());
|
||||
#endif
|
||||
return eStateRunning;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue