[LSan] Introduce a callback mechanism to allow adding data reachable from ThreadContexts to the frontier.

This mechanism is intended to provide a way to treat the `arg` pointer
of a created (but not yet started) thread as reachable. In future
patches this will be implemented in `GetAdditionalThreadContextPtrs`.

A separate implementation of `GetAdditionalThreadContextPtrs` exists
for ASan and LSan runtimes because they need to be implemented
differently in future patches.

rdar://problem/63537240

Differential Revision: https://reviews.llvm.org/D95183
This commit is contained in:
Dan Liew 2021-01-21 15:48:41 -08:00
parent 6fe193bf27
commit dd922bc2a6
4 changed files with 46 additions and 0 deletions

View File

@ -1183,6 +1183,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
m->lsan_tag = __lsan::kIgnored;
return kIgnoreObjectSuccess;
}
void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
// This function can be used to treat memory reachable from `tctx` as live.
// This is useful for threads that have been created but not yet started.
// This is currently a no-op because the ASan `pthread_create()` interceptor
// blocks until the child thread starts which keeps the thread's `arg` pointer
// live.
}
} // namespace __lsan
// ---------------------- Interface ---------------- {{{1

View File

@ -309,6 +309,16 @@ IgnoreObjectResult IgnoreObjectLocked(const void *p) {
return kIgnoreObjectInvalid;
}
}
void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs) {
// This function can be used to treat memory reachable from `tctx` as live.
// This is useful for threads that have been created but not yet started.
// This is currently a no-op because the LSan `pthread_create()` interceptor
// blocks until the child thread starts which keeps the thread's `arg` pointer
// live.
}
} // namespace __lsan
using namespace __lsan;

View File

@ -253,6 +253,27 @@ extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls(
pid_t, void (*cb)(void *, void *, uptr, void *), void *);
#endif
static void ProcessThreadRegistry(Frontier *frontier) {
InternalMmapVector<uptr> ptrs;
GetThreadRegistryLocked()->RunCallbackForEachThreadLocked(
GetAdditionalThreadContextPtrs, &ptrs);
for (uptr i = 0; i < ptrs.size(); ++i) {
void *ptr = reinterpret_cast<void *>(ptrs[i]);
uptr chunk = PointsIntoChunk(ptr);
if (!chunk)
continue;
LsanMetadata m(chunk);
if (!m.allocated())
continue;
// Mark as reachable and add to frontier.
LOG_POINTERS("Treating pointer %p from ThreadContext as reachable\n", ptr);
m.set_tag(kReachable);
frontier->push_back(chunk);
}
}
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
@ -364,6 +385,9 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
#endif
}
}
// Add pointers reachable from ThreadContexts
ProcessThreadRegistry(frontier);
}
#endif // SANITIZER_FUCHSIA

View File

@ -50,6 +50,7 @@
namespace __sanitizer {
class FlagParser;
class ThreadRegistry;
class ThreadContextBase;
struct DTLS;
}
@ -142,6 +143,7 @@ InternalMmapVector<RootRegion> const *GetRootRegions();
void ScanRootRegion(Frontier *frontier, RootRegion const &region,
uptr region_begin, uptr region_end, bool is_readable);
void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg);
void GetAdditionalThreadContextPtrs(ThreadContextBase *tctx, void *ptrs);
// Run stoptheworld while holding any platform-specific locks, as well as the
// allocator and thread registry locks.
void LockStuffAndStopTheWorld(StopTheWorldCallback callback,