• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
6 #define BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
7 
8 #include <stddef.h>
9 
10 #include "base/base_export.h"
11 #include "build/build_config.h"
12 
13 namespace base {
14 namespace allocator {
15 
16 // Allocator Shim API. Allows to:
17 //  - Configure the behavior of the allocator (what to do on OOM failures).
18 //  - Install new hooks (AllocatorDispatch) in the allocator chain.
19 
20 // When this shim layer is enabled, the route of an allocation is as-follows:
21 //
22 // [allocator_shim_override_*.h] Intercept malloc() / operator new calls:
23 //   The override_* headers define the symbols required to intercept calls to
24 //   malloc() and operator new (if not overridden by specific C++ classes).
25 //
26 // [allocator_shim.cc] Routing allocation calls to the shim:
27 //   The headers above route the calls to the internal ShimMalloc(), ShimFree(),
28 //   ShimCppNew() etc. methods defined in allocator_shim.cc.
29 //   These methods will: (1) forward the allocation call to the front of the
30 //   AllocatorDispatch chain. (2) perform security hardenings (e.g., might
31 //   call std::new_handler on OOM failure).
32 //
33 // [allocator_shim_default_dispatch_to_*.cc] The AllocatorDispatch chain:
34 //   It is a singly linked list where each element is a struct with function
35 //   pointers (|malloc_function|, |free_function|, etc). Normally the chain
36 //   consists of a single AllocatorDispatch element, herein called
37 //   the "default dispatch", which is statically defined at build time and
38 //   ultimately routes the calls to the actual allocator defined by the build
39 //   config (tcmalloc, glibc, ...).
40 //
41 // It is possible to dynamically insert further AllocatorDispatch stages
42 // to the front of the chain, for debugging / profiling purposes.
43 //
44 // All the functions must be thred safe. The shim does not enforce any
45 // serialization. This is to route to thread-aware allocators (e.g, tcmalloc)
46 // wihout introducing unnecessary perf hits.
47 
48 struct AllocatorDispatch {
49   using AllocFn = void*(const AllocatorDispatch* self,
50                         size_t size,
51                         void* context);
52   using AllocZeroInitializedFn = void*(const AllocatorDispatch* self,
53                                        size_t n,
54                                        size_t size,
55                                        void* context);
56   using AllocAlignedFn = void*(const AllocatorDispatch* self,
57                                size_t alignment,
58                                size_t size,
59                                void* context);
60   using ReallocFn = void*(const AllocatorDispatch* self,
61                           void* address,
62                           size_t size,
63                           void* context);
64   using FreeFn = void(const AllocatorDispatch* self,
65                       void* address,
66                       void* context);
67   // Returns the best available estimate for the actual amount of memory
68   // consumed by the allocation |address|. If possible, this should include
69   // heap overhead or at least a decent estimate of the full cost of the
70   // allocation. If no good estimate is possible, returns zero.
71   using GetSizeEstimateFn = size_t(const AllocatorDispatch* self,
72                                    void* address,
73                                    void* context);
74   using BatchMallocFn = unsigned(const AllocatorDispatch* self,
75                                  size_t size,
76                                  void** results,
77                                  unsigned num_requested,
78                                  void* context);
79   using BatchFreeFn = void(const AllocatorDispatch* self,
80                            void** to_be_freed,
81                            unsigned num_to_be_freed,
82                            void* context);
83   using FreeDefiniteSizeFn = void(const AllocatorDispatch* self,
84                                   void* ptr,
85                                   size_t size,
86                                   void* context);
87 
88   AllocFn* const alloc_function;
89   AllocZeroInitializedFn* const alloc_zero_initialized_function;
90   AllocAlignedFn* const alloc_aligned_function;
91   ReallocFn* const realloc_function;
92   FreeFn* const free_function;
93   GetSizeEstimateFn* const get_size_estimate_function;
94   BatchMallocFn* const batch_malloc_function;
95   BatchFreeFn* const batch_free_function;
96   FreeDefiniteSizeFn* const free_definite_size_function;
97 
98   const AllocatorDispatch* next;
99 
100   // |default_dispatch| is statically defined by one (and only one) of the
101   // allocator_shim_default_dispatch_to_*.cc files, depending on the build
102   // configuration.
103   static const AllocatorDispatch default_dispatch;
104 };
105 
106 // When true makes malloc behave like new, w.r.t calling the new_handler if
107 // the allocation fails (see set_new_mode() in Windows).
108 BASE_EXPORT void SetCallNewHandlerOnMallocFailure(bool value);
109 
110 // Allocates |size| bytes or returns nullptr. It does NOT call the new_handler,
111 // regardless of SetCallNewHandlerOnMallocFailure().
112 BASE_EXPORT void* UncheckedAlloc(size_t size);
113 
114 // Inserts |dispatch| in front of the allocator chain. This method is
115 // thread-safe w.r.t concurrent invocations of InsertAllocatorDispatch().
116 // The callers have responsibility for inserting a single dispatch no more
117 // than once.
118 BASE_EXPORT void InsertAllocatorDispatch(AllocatorDispatch* dispatch);
119 
120 // Test-only. Rationale: (1) lack of use cases; (2) dealing safely with a
121 // removal of arbitrary elements from a singly linked list would require a lock
122 // in malloc(), which we really don't want.
123 BASE_EXPORT void RemoveAllocatorDispatchForTesting(AllocatorDispatch* dispatch);
124 
125 #if defined(OS_MACOSX)
126 // On macOS, the allocator shim needs to be turned on during runtime.
127 BASE_EXPORT void InitializeAllocatorShim();
128 #endif  // defined(OS_MACOSX)
129 
130 }  // namespace allocator
131 }  // namespace base
132 
133 #endif  // BASE_ALLOCATOR_ALLOCATOR_SHIM_H_
134