<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:
Greg Clayton 2013-07-30 00:23:06 +00:00
parent 4ed04e2ee3
commit 6e10f149c4
3 changed files with 207 additions and 1 deletions

View File

@ -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

View File

@ -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)
{

View File

@ -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;
}