Add support to allocators to enumerate allocations out-of-process.
This work is part of a multi patch series to implement a malloc zone
enumerator on Darwin. On Darwin zone enumerators work out-of-process. A
memory analysis tool wishing to inspect a malloc zone of a target
process, pauses the target process, dlopen()'s the target process's
allocator library (in our case asan/lsan/tsan) into itself and then
calls the malloc zone enumeration function (from the dlopened library)
to inspect the target process on the analysis process's behalf.
In order to implement this a first step is to allow the sanitizer
allocators to be enumerated out-of-process. This is what this
patch focuses on. Other necessary parts will be implemented in
later patches.
Earlier attempts at this patch suffered from code duplication where the
in-process and out-of-process code paths were independent which would
have lead to code maintenance problems in the future. This patch
unifies both the in-process and out-of-process code paths into a single
implementation using an ObjectView abstraction.
The ObjectView abstraction is an interface that abstracts away (most
of) the differences between in-process and out-of-process enumeration in
a type safe and efficient manner.
The LocalObjectView implementation of this abstraction is for
in-process enumeration and tries to be efficient by not storing
unnecessary data and by not performing any allocations or copy
operations.
The RemoteObjectView implementation of this abstraction is for
out-of-process enumeration. It automatically handles copying data from
another process and allocating/freeing storage for that copy.
Under the hood this implementation uses a new VMReadContext class to do
the actual copying and then uses a storage class to manage
the storage.
VMReadContext is a low-level abstraction for reading the memory of
another process. It is not intended to be used directly.
Existing allocator methods (such as ForEachChunk) simply create a
LocalObjectView (which is essentially acts just like a this pointer)
and call a static method with a OOP suffix that does the actual work.
The static methods with the OOP suffix are templated over a
ObjectView type which can either be LocalObjectView or some
instantiation of RemoteObjectView and also take a pointer to an
instance of that type. The choice to make these OOP methods being
static is deliberate because it means there is no this pointer and
so it is harder to accidenly call normal instance methods which could be
unsafe.
The Sanitizer allocator unit tests have been updated to do enumeration
using the RemoteObjectView interface in addition to the
LocalObjectView interface so that we can check that
- The code correctly compiles when instantiated with RemoteObjectView (In the sanitizer libraries it currently is never instantiated with this type).
- That the copying and allocation steps of RemoteObjectView work correctly.
rdar://problem/45284065
I'd avoid this typedefs use in implementation only
for sizeof please use actual variables, e.g. sizeof(*this)
other few places just decltype(*this)