| This document describes how malloc / new calls are routed in the various Chrome |
| platforms. |
| |
| Bare in mind that the chromium codebase does not always just use `malloc()`. |
| Some examples: |
| - Large parts of the renderer (Blink) use two home-brewed allocators, |
| PartitionAlloc and BlinkGC (Oilpan). |
| - Some subsystems, such as the V8 JavaScript engine, handle memory management |
| autonomously. |
| - Various parts of the codebase use abstractions such as `SharedMemory` or |
| `DiscardableMemory` which, similarly to the above, have their own page-level |
| memory management. |
| |
| Background |
| ---------- |
| The `allocator` target defines at compile-time the platform-specific choice of |
| the allocator and extra-hooks which services calls to malloc/new. The relevant |
| build-time flags involved are `use_allocator` and `use_allocator_shim`. |
| |
| The default choices are as follows: |
| |
| **Windows** |
| `use_allocator: winheap`, the default Windows heap. |
| Additionally, `static_library` (i.e. non-component) builds have a shim |
| layer wrapping malloc/new, which is controlled by `use_allocator_shim`. |
| The shim layer provides extra security features, such as preventing large |
| allocations that can hit signed vs. unsigned bugs in third_party code. |
| |
| **Linux Desktop / CrOS** |
| `use_allocator: tcmalloc`, a forked copy of tcmalloc which resides in |
| `third_party/tcmalloc/chromium`. Setting `use_allocator: none` causes the build |
| to fall back to the system (Glibc) symbols. |
| |
| **Android** |
| `use_allocator: none`, always use the allocator symbols coming from Android's |
| libc (Bionic). As it is developed as part of the OS, it is considered to be |
| optimized for small devices and more memory-efficient than other choices. |
| The actual implementation backing malloc symbols in Bionic is up to the board |
| config and can vary (typically *dlmalloc* or *jemalloc* on most Nexus devices). |
| |
| **Mac/iOS** |
| `use_allocator: none`, we always use the system's allocator implementation. |
| |
| In addition, when building for `asan` / `msan` both the allocator and the shim |
| layer are disabled. |
| |
| Layering and build deps |
| ----------------------- |
| The `allocator` target provides both the source files for tcmalloc (where |
| applicable) and the linker flags required for the Windows shim layer. |
| The `base` target is (almost) the only one depending on `allocator`. No other |
| targets should depend on it, with the exception of the very few executables / |
| dynamic libraries that don't depend, either directly or indirectly, on `base` |
| within the scope of a linker unit. |
| |
| More importantly, **no other place outside of `/base` should depend on the |
| specific allocator** (e.g., directly include `third_party/tcmalloc`). |
| If such a functional dependency is required that should be achieved using |
| abstractions in `base` (see `/base/allocator/allocator_extension.h` and |
| `/base/memory/`) |
| |
| **Why `base` depends on `allocator`?** |
| Because it needs to provide services that depend on the actual allocator |
| implementation. In the past `base` used to pretend to be allocator-agnostic |
| and get the dependencies injected by other layers. This ended up being an |
| inconsistent mess. |
| See the [allocator cleanup doc][url-allocator-cleanup] for more context. |
| |
| Linker unit targets (executables and shared libraries) that depend in some way |
| on `base` (most of the targets in the codebase) get automatically the correct |
| set of linker flags to pull in tcmalloc or the Windows shim-layer. |
| |
| |
| Source code |
| ----------- |
| This directory contains just the allocator (i.e. shim) layer that switches |
| between the different underlying memory allocation implementations. |
| |
| The tcmalloc library originates outside of Chromium and exists in |
| `../../third_party/tcmalloc` (currently, the actual location is defined in the |
| allocator.gyp file). The third party sources use a vendor-branch SCM pattern to |
| track Chromium-specific changes independently from upstream changes. |
| |
| The general intent is to push local changes upstream so that over |
| time we no longer need any forked files. |
| |
| |
| Unified allocator shim |
| ---------------------- |
| On most platforms, Chrome overrides the malloc / operator new symbols (and |
| corresponding free / delete and other variants). This is to enforce security |
| checks and lately to enable the |
| [memory-infra heap profiler][url-memory-infra-heap-profiler]. |
| Historically each platform had its special logic for defining the allocator |
| symbols in different places of the codebase. The unified allocator shim is |
| a project aimed to unify the symbol definition and allocator routing logic in |
| a central place. |
| |
| - Full documentation: [Allocator shim design doc][url-allocator-shim]. |
| - Current state: Available and enabled by default on Android, CrOS, Linux, |
| Mac OS and Windows. |
| - Tracking bug: [https://crbug.com/550886][crbug.com/550886]. |
| - Build-time flag: `use_allocator_shim`. |
| |
| **Overview of the unified allocator shim** |
| The allocator shim consists of three stages: |
| ``` |
| +-------------------------+ +-----------------------+ +----------------+ |
| | malloc & friends | -> | shim layer | -> | Routing to | |
| | symbols definition | | implementation | | allocator | |
| +-------------------------+ +-----------------------+ +----------------+ |
| | - libc symbols (malloc, | | - Security checks | | - tcmalloc | |
| | calloc, free, ...) | | - Chain of dispatchers| | - glibc | |
| | - C++ symbols (operator | | that can intercept | | - Android | |
| | new, delete, ...) | | and override | | bionic | |
| | - glibc weak symbols | | allocations | | - WinHeap | |
| | (__libc_malloc, ...) | +-----------------------+ +----------------+ |
| +-------------------------+ |
| ``` |
| |
| **1. malloc symbols definition** |
| This stage takes care of overriding the symbols `malloc`, `free`, |
| `operator new`, `operator delete` and friends and routing those calls inside the |
| allocator shim (next point). |
| This is taken care of by the headers in `allocator_shim_override_*`. |
| |
| *On Linux/CrOS*: the allocator symbols are defined as exported global symbols |
| in `allocator_shim_override_libc_symbols.h` (for `malloc`, `free` and friends) |
| and in `allocator_shim_override_cpp_symbols.h` (for `operator new`, |
| `operator delete` and friends). |
| This enables proper interposition of malloc symbols referenced by the main |
| executable and any third party libraries. Symbol resolution on Linux is a breadth first search that starts from the root link unit, that is the executable |
| (see EXECUTABLE AND LINKABLE FORMAT (ELF) - Portable Formats Specification). |
| Additionally, when tcmalloc is the default allocator, some extra glibc symbols |
| are also defined in `allocator_shim_override_glibc_weak_symbols.h`, for subtle |
| reasons explained in that file. |
| The Linux/CrOS shim was introduced by |
| [crrev.com/1675143004](https://crrev.com/1675143004). |
| |
| *On Android*: load-time symbol interposition (unlike the Linux/CrOS case) is not |
| possible. This is because Android processes are `fork()`-ed from the Android |
| zygote, which pre-loads libc.so and only later native code gets loaded via |
| `dlopen()` (symbols from `dlopen()`-ed libraries get a different resolution |
| scope). |
| In this case, the approach instead of wrapping symbol resolution at link time |
| (i.e. during the build), via the `--Wl,-wrap,malloc` linker flag. |
| The use of this wrapping flag causes: |
| - All references to allocator symbols in the Chrome codebase to be rewritten as |
| references to `__wrap_malloc` and friends. The `__wrap_malloc` symbols are |
| defined in the `allocator_shim_override_linker_wrapped_symbols.h` and |
| route allocator calls inside the shim layer. |
| - The reference to the original `malloc` symbols (which typically is defined by |
| the system's libc.so) are accessible via the special `__real_malloc` and |
| friends symbols (which will be relocated, at load time, against `malloc`). |
| |
| In summary, this approach is transparent to the dynamic loader, which still sees |
| undefined symbol references to malloc symbols. |
| These symbols will be resolved against libc.so as usual. |
| More details in [crrev.com/1719433002](https://crrev.com/1719433002). |
| |
| **2. Shim layer implementation** |
| This stage contains the actual shim implementation. This consists of: |
| - A singly linked list of dispatchers (structs with function pointers to `malloc`-like functions). Dispatchers can be dynamically inserted at runtime |
| (using the `InsertAllocatorDispatch` API). They can intercept and override |
| allocator calls. |
| - The security checks (suicide on malloc-failure via `std::new_handler`, etc). |
| This happens inside `allocator_shim.cc` |
| |
| **3. Final allocator routing** |
| The final element of the aforementioned dispatcher chain is statically defined |
| at build time and ultimately routes the allocator calls to the actual allocator |
| (as described in the *Background* section above). This is taken care of by the |
| headers in `allocator_shim_default_dispatch_to_*` files. |
| |
| |
| Appendixes |
| ---------- |
| **How does the Windows shim layer replace the malloc symbols?** |
| The mechanism for hooking LIBCMT in Windows is rather tricky. The core |
| problem is that by default, the Windows library does not declare malloc and |
| free as weak symbols. Because of this, they cannot be overridden. To work |
| around this, we start with the LIBCMT.LIB, and manually remove all allocator |
| related functions from it using the visual studio library tool. Once removed, |
| we can now link against the library and provide custom versions of the |
| allocator related functionality. |
| See the script `preb_libc.py` in this folder. |
| |
| Related links |
| ------------- |
| - [Unified allocator shim doc - Feb 2016][url-allocator-shim] |
| - [Allocator cleanup doc - Jan 2016][url-allocator-cleanup] |
| - [Proposal to use PartitionAlloc as default allocator](https://crbug.com/339604) |
| - [Memory-Infra: Tools to profile memory usage in Chrome](/docs/memory-infra/README.md) |
| |
| [url-allocator-cleanup]: https://docs.google.com/document/d/1V77Kgp_4tfaaWPEZVxNevoD02wXiatnAv7Ssgr0hmjg/edit?usp=sharing |
| [url-memory-infra-heap-profiler]: /docs/memory-infra/heap_profiler.md |
| [url-allocator-shim]: https://docs.google.com/document/d/1yKlO1AO4XjpDad9rjcBOI15EKdAGsuGO_IeZy0g0kxo/edit?usp=sharing |