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,34 @@ // 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 + typename ObjectView::template SmallAllocTy
header_ptr_view( + header_ptr_addr); + Header *t = *(header_ptr_view.GetLocalAddress()); + 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); + + if (ObjectView::IsLocal()) { + // Consistency check: verify that the array did not change. + CHECK_EQ(chunks_[i], t); + CHECK_EQ(chunks_[i]->chunk_idx, i); + } } } private: + typedef LargeMmapAllocator ThisT; + using ObjectView = ObjectViewT; + struct Header { uptr map_beg; uptr map_size; @@ -316,4 +334,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,80 @@ +//===-- 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 +#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() {} + + // Forbid copying. + LocalObjectView(const LocalObjectView&) = delete; + LocalObjectView(const LocalObjectView&& other) = delete; + LocalObjectView& operator=(const LocalObjectView&) = delete; + LocalObjectView& operator=(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; } + + // `LargeAllocTy` and `SmallAllocTy` are intended for use by generic + // in/out-of-process code to make decisions on what type of storage is + // required for an object view. + // + // For views on local objects no copy is necessary so we just alias + // `LocalObjectView` so that no storage allocations are performed. + template + using LargeAllocTy = LocalObjectView; + template + using SmallAllocTy = LocalObjectView; +}; + +}; // namespace __sanitizer +#endif