platform_system_core/libmemunreachable
Josh Gao 69d2f98197 adb: fix fd double close, Subprocess lifetime issue.
This commit fixes two somewhat related issues in shell_service.

  - The fd returned by StartSubprocess is owned by a unique_fd
    contained in the Subprocess object, but also gets closed by the
    caller. Resolve this by duping the returned file descriptor.

  - A Subprocess object can be destroyed immediately after its initial
    construction in StartSubprocess if we're sufficiently unlucky.
    Split up the fork/exec and "start management thread" steps, so that
    we can safely do everything we need to do on the Subprocess before
    handing it over to the thread that'll eventually destroy it.

Also includes squashed patches from AOSP master that allow for use of
unique_fd inside adb.

Bug: http://b/29254462
Change-Id: Id9cf0b7e7a7293bee7176919edc758597691c636
(cherry picked from commit c0e6e40cc9)
(cherry picked from commit 54c72aaccc)
(cherry picked from commit 2c5d1d7cd9)
(cherry picked from commit 2a7b86337f)
(cherry picked from commit 13ea01db45)
(cherry picked from commit 344778da41)
2016-06-20 14:51:05 -07:00
..
include/memunreachable Combine leaks with same stacktrace 2016-03-04 22:40:34 -08:00
tests adb: fix fd double close, Subprocess lifetime issue. 2016-06-20 14:51:05 -07:00
Allocator.cpp Compile some tests for the host 2016-03-04 16:39:51 -08:00
Allocator.h Combine leaks with same stacktrace 2016-03-04 22:40:34 -08:00
Android.mk Fix mac build 2016-03-07 17:19:28 -08:00
anon_vma_naming.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
bionic.h Compile some tests for the host 2016-03-04 16:39:51 -08:00
HeapWalker.cpp Silently ignore duplicate heap entries 2016-04-28 16:20:40 -07:00
HeapWalker.h Silently ignore duplicate heap entries 2016-04-28 16:20:40 -07:00
Leak.h Combine leaks with same stacktrace 2016-03-04 22:40:34 -08:00
LeakFolding.cpp Combine leaks with same stacktrace 2016-03-04 22:40:34 -08:00
LeakFolding.h Combine leaks with same stacktrace 2016-03-04 22:40:34 -08:00
LeakPipe.cpp imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
LeakPipe.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
LineBuffer.cpp imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
LineBuffer.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
LinkedList.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
log.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
MemUnreachable.cpp Add ABI to leak report 2016-03-04 22:40:34 -08:00
ProcessMappings.cpp adb: fix fd double close, Subprocess lifetime issue. 2016-06-20 14:51:05 -07:00
ProcessMappings.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
PtracerThread.cpp imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
PtracerThread.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
README.md imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
ScopedAlarm.h Compile some tests for the host 2016-03-04 16:39:51 -08:00
ScopedDisableMalloc.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
ScopedPipe.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
ScopedSignalHandler.h Handle segfaults while walking native heap 2016-04-28 16:20:40 -07:00
Semaphore.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00
Tarjan.h Fold leaks that are referenced by other leaks 2016-03-04 16:39:59 -08:00
ThreadCapture.cpp adb: fix fd double close, Subprocess lifetime issue. 2016-06-20 14:51:05 -07:00
ThreadCapture.h imprecise mark and sweep native memory leak detector 2016-02-19 00:49:36 -08:00

libmemunreachable

Introduction

libmemunreachable is a zero-overhead native memory leak detector. It uses an imprecise mark-and-sweep garbage collector pass over all native memory, reporting any unreachable blocks as leaks. It is similar to the Heap Checker from tcmalloc, but with a few key differences to remove the overhead. Instead of instrumenting every call to malloc and free, it queries the allocator (jemalloc) for active allocations when leak detection is requested. In addition, it performs a very short stop-the-world data collection on the main process, and then forks a copy of the process to perform the mark-and-sweep, minimizing disruption to the original process.

In the default (zero-overhead) mode, the returned data on leaks is limited to the address, approximate (upper bound) size, and the the first 32 bytes of the contents of the leaked allocation. If malloc_debug backtraces are enabled they will be included in the leak information, but backtracing allocations requires significant overhead.


Usage

C interface

bool LogUnreachableMemory(bool log_contents, size_t limit)

Writes a description of leaked memory to the log. A summary is always written, followed by details of up to limit leaks. If log_contents is true, details include up to 32 bytes of the contents of each leaked allocation. Returns true if leak detection succeeded.

bool NoLeaks()

Returns true if no unreachable memory was found.

C++ interface

####bool GetUnreachableMemory(UnreachableMemoryInfo& info, size_t limit = 100)#### Updates an UnreachableMemoryInfo object with information on leaks, including details on up to limit leaks. Returns true if leak detection succeeded.

std::string GetUnreachableMemoryString(bool log_contents = false, size_t limit = 100)

Returns a description of leaked memory. A summary is always written, followed by details of up to limit leaks. If log_contents is true, details include up to 32 bytes of the contents of each leaked allocation. Returns true if leak detection succeeded.

Implementation

The sequence of steps required to perform a leak detection pass is divided into three processes - the original process, the collection process, and the sweeper process.

  1. Original process: Leak detection is requested by calling GetUnreachableMemory()
  2. Allocations are disabled using malloc_disable()
  3. The collection process is spawned. The collection process is similar to a normal fork() child process, except that it shares the address space of the parent - any writes by the original process are visible to the collection process, and vice-versa.
  4. Collection process: All threads in the original process are paused with ptrace().
  5. Registers contents, active stack areas, and memory mapping information are collected.
  6. Original process: Allocations are re-enabled using malloc_enable(), but all threads are still paused with ptrace().
  7. Collection process: The sweeper process is spawned using a normal fork(). The sweeper process has a copy of all memory from the original process, including all the data collected by the collection process.
  8. Collection process releases all threads from ptrace and exits
  9. Original process: All threads continue, the thread that called GetUnreachableMemory() blocks waiting for leak data over a pipe.
  10. Sweeper process: A list of all active allocations is produced by examining the memory mappings and calling malloc_iterate() on any heap mappings.
  11. A list of all roots is produced from globals (.data and .bss sections of binaries), and registers and stacks from each thread.
  12. The mark-and-sweep pass is performed starting from roots.
  13. Unmarked allocations are sent over the pipe back to the original process.

Components

  • MemUnreachable.cpp: Entry points, implements the sequencing described above.
  • PtracerThread.cpp: Used to clone the collection process with shared address space.
  • ThreadCapture.cpp: Pauses threads in the main process and collects register contents.
  • ProcessMappings.cpp: Collects snapshots of /proc/pid/maps.
  • HeapWalker.cpp: Performs the mark-and-sweep pass over active allocations.
  • LeakPipe.cpp: transfers data describing leaks from the sweeper process to the original process.

Heap allocator requirements

libmemunreachable requires a small interface to the allocator in order to collect information about active allocations.

  • malloc_disable(): prevent any thread from mutating internal allocator state.
  • malloc enable(): re-enable allocations in all threads.
  • malloc_iterate(): call a callback on each active allocation in a given heap region.
  • malloc_backtrace(): return the backtrace from when the allocation at the given address was allocated, if it was collected.