Index: lib/sanitizer_common/CMakeLists.txt =================================================================== --- lib/sanitizer_common/CMakeLists.txt +++ lib/sanitizer_common/CMakeLists.txt @@ -144,6 +144,7 @@ sanitizer_libignore.h sanitizer_linux.h sanitizer_list.h + sanitizer_local_object_view.h sanitizer_mac.h sanitizer_malloc_mac.inc sanitizer_mutex.h Index: lib/sanitizer_common/sanitizer_allocator.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator.h +++ lib/sanitizer_common/sanitizer_allocator.h @@ -14,12 +14,13 @@ #ifndef SANITIZER_ALLOCATOR_H #define SANITIZER_ALLOCATOR_H -#include "sanitizer_internal_defs.h" #include "sanitizer_common.h" +#include "sanitizer_internal_defs.h" +#include "sanitizer_lfstack.h" #include "sanitizer_libc.h" #include "sanitizer_list.h" +#include "sanitizer_local_object_view.h" #include "sanitizer_mutex.h" -#include "sanitizer_lfstack.h" #include "sanitizer_procmaps.h" namespace __sanitizer { Index: lib/sanitizer_common/sanitizer_allocator_secondary.h =================================================================== --- lib/sanitizer_common/sanitizer_allocator_secondary.h +++ lib/sanitizer_common/sanitizer_allocator_secondary.h @@ -68,7 +68,8 @@ // The main purpose of this allocator is to cover large and rare allocation // sizes not covered by more efficient allocators (e.g. SizeClassAllocator64). template + class PtrArrayT = DefaultLargeMmapAllocatorPtrArray, + template class ObjectViewT = LocalObjectView> class LargeMmapAllocator { public: void InitLinkerInitialized() { @@ -271,17 +272,32 @@ // Iterate over all existing chunks. // The allocator must be locked when calling this function. void ForEachChunk(ForEachChunkCallback callback, void *arg) { - EnsureSortedChunks(); // Avoid doing the sort while iterating. + if (ObjectView::IsLocal()) { + // Avoid doing the sort while iterating. We don't do + // this for out-of-process enumeration because we can't + // perform writes. + EnsureSortedChunks(); + } for (uptr i = 0; i < n_chunks_; i++) { - auto t = chunks_[i]; + // Compute address of header pointer + Header **header_ptr_addr = &(chunks_[i]); + // Copy header pointer into this process + auto t = ObjectView::MakeView(header_ptr_addr); + callback(reinterpret_cast(GetUser(t)), arg); + // Consistency check: verify that the array did not change. - CHECK_EQ(chunks_[i], t); - CHECK_EQ(chunks_[i]->chunk_idx, i); + auto t2 = ObjectView::MakeView(&chunks_[i]); + CHECK_EQ(static_cast
(t), static_cast
(t2)); + auto header_view = ObjectView::MakeView(static_cast
(t2)); + CHECK_EQ(static_cast
(header_view).chunk_idx, i); } } private: + typedef LargeMmapAllocator ThisT; + using ObjectView = ObjectViewT; + struct Header { uptr map_beg; uptr map_size; @@ -316,4 +332,3 @@ } stats; StaticSpinMutex mutex_; }; - Index: lib/sanitizer_common/sanitizer_local_object_view.h =================================================================== --- /dev/null +++ lib/sanitizer_common/sanitizer_local_object_view.h @@ -0,0 +1,85 @@ +//===-- sanitizer_local_object_view.h ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// The "local" (i.e. in-process) implementation of the `ObjectView` abstraction. +// +//===----------------------------------------------------------------------===// +#ifndef SANITIZER_LOCAL_OBJECT_VIEW_H +#define SANITIZER_LOCAL_OBJECT_VIEW_H +#include "sanitizer_internal_defs.h" + +namespace __sanitizer { + +template +struct ObjectViewBase { + static uptr GetSize() { return sizeof(T); } +}; + +// Provides the implementation of the `ObjectView` abstraction for efficient +// views on in-process objects of type `ObjectTy`. This implementation does not +// make copies of objects and thus does not allocate any storage for these +// copies. +// +// Generic in/out-of-process code should only use the subset of the interface +// shared between `LocalObjectView` and `RemoteObjectView`. +template +struct LocalObjectView : ObjectViewBase { + private: + uptr target_address; + + public: + using ObjectType = ObjectTy; + ALWAYS_INLINE LocalObjectView(uptr target_address) + : target_address(target_address) {} + ALWAYS_INLINE LocalObjectView(ObjectTy* target_address) + : LocalObjectView(reinterpret_cast(target_address)) {} + ~LocalObjectView() {} + + // Allow moving + LocalObjectView(LocalObjectView&& other) = default; + + // Forbid assignment + LocalObjectView& operator=(const LocalObjectView&) = delete; + LocalObjectView& operator=(LocalObjectView&&) = delete; + LocalObjectView(const LocalObjectView&) = delete; + + // Returns true iff the target address is memory + // local to this process. + ALWAYS_INLINE static bool IsLocal() { return true; } + + // Returns true iff it is safe to dereference the pointer returned by + // `GetLocalAddress()`. + ALWAYS_INLINE bool IsValid() const { return true; } + + // Return the address of an object of type `ObjectTy` in the current process. + ALWAYS_INLINE ObjectTy* GetLocalAddress() const { + return reinterpret_cast(target_address); + } + + // Return the address of an object of type `ObjectTy` in the target process. + ALWAYS_INLINE uptr GetTargetAddress() { return target_address; } + + // Convenience functions for constructing views into other objects. + template + static LocalObjectView MakeView( + OtherObjectTy* target_address) { + return LocalObjectView(target_address); + } + template + static LocalObjectView MakeView(uptr target_address) { + return LocalObjectView(target_address); + } + + // Implicit conversion operator so RemoteObjectView + // can be treated like a `ObjectTy&`. + operator ObjectTy&() const { return *(GetLocalAddress()); } +}; + +}; // namespace __sanitizer +#endif