Background:
ThreadPlan objects store a cached pointer to the associated Thread. To quote
the code:
We don't cache the thread pointer over resumes. This
Thread might go away, and another Thread represent
// the same underlying object on a later stop.
This can happen only when using an operating system plugin with
os-plugin-reports-all-threads = false (a new feature); otherwise, the
ThreadPlan will be wiped away when the Thread is.
Previously, this cached pointer was unowned, and ThreadPlan attempted to
prevent it from becoming stale by invalidating it in WillResume, reasoning that
the list of threads would only change whwen the target is running. However, it
turns out that the pointer can be re-cached after it's invalidated but before
the target actually starts running. At least one path where this happens is
ThreadPlan::ShouldReportRun -> GetPreviousPlan -> GetThread.
It might be possible to fix this by invalidating the pointer from other places,
but that seems unnecessarily risky and complicated. Instead, just keep around
a ThreadSP and check IsValid(), which becomes false when Thread::DestroyThread()
is called.
Note: This does not create a retain cycle because Thread does not own
ThreadPlans. (Even if it did, Thread::DestroyThread resets all of the thread's
owned pointers.)
As for testing, I made a small change to the existing reports-all-threads test
which causes it to trigger the use-after-free without the rest of the commit.
clang-tidy: error: 'lldb/Target/Process.h' file not found [clang-diagnostic-error]
not useful