diff options
author | Greg Clayton <gclayton@apple.com> | 2013-07-30 00:23:06 +0000 |
---|---|---|
committer | Greg Clayton <gclayton@apple.com> | 2013-07-30 00:23:06 +0000 |
commit | e4923ddaa18bf003e339e6ab33bfd137a632fc0f (patch) | |
tree | 16c5945b76cc002ce58f6af66a20eab29ac92802 | |
parent | 21f98a38a0cfa10b9935248f1b3628b5ba914402 (diff) | |
download | lldb-e4923ddaa18bf003e339e6ab33bfd137a632fc0f.tar.gz |
<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.
git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@187395 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/lldb/Target/ThreadPlan.h | 54 | ||||
-rw-r--r-- | source/Target/Thread.cpp | 13 | ||||
-rw-r--r-- | source/Target/ThreadPlan.cpp | 141 |
3 files changed, 207 insertions, 1 deletions
diff --git a/include/lldb/Target/ThreadPlan.h b/include/lldb/Target/ThreadPlan.h index 3d95a0924..3c83fd1b9 100644 --- a/include/lldb/Target/ThreadPlan.h +++ b/include/lldb/Target/ThreadPlan.h @@ -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 diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp index 401eac2b2..b65434bf9 100644 --- a/source/Target/Thread.cpp +++ b/source/Target/Thread.cpp @@ -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) { diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp index ba35db19c..11240dbe2 100644 --- a/source/Target/ThreadPlan.cpp +++ b/source/Target/ThreadPlan.cpp @@ -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; +} |