AllocPolicy.h (6114B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * An allocation policy concept, usable for structures and algorithms to 9 * control how memory is allocated and how failures are handled. 10 */ 11 12 #ifndef mozilla_AllocPolicy_h 13 #define mozilla_AllocPolicy_h 14 15 #include "mozilla/Assertions.h" 16 #include "mozilla/CheckedArithmetic.h" 17 #include "mozilla/Likely.h" 18 19 #include <cstddef> 20 #include <cstdlib> 21 22 namespace mozilla { 23 24 /* 25 * Allocation policies are used to implement the standard allocation behaviors 26 * in a customizable way. Additionally, custom behaviors may be added to these 27 * behaviors, such as additionally reporting an error through an out-of-band 28 * mechanism when OOM occurs. The concept modeled here is as follows: 29 * 30 * - public copy constructor, assignment, destructor 31 * - template <typename T> T* maybe_pod_malloc(size_t) 32 * Fallible, but doesn't report an error on OOM. 33 * - template <typename T> T* maybe_pod_calloc(size_t) 34 * Fallible, but doesn't report an error on OOM. 35 * - template <typename T> T* maybe_pod_realloc(T*, size_t, size_t) 36 * Fallible, but doesn't report an error on OOM. The old allocation 37 * size is passed in, in addition to the new allocation size requested. 38 * - template <typename T> T* pod_malloc(size_t) 39 * Responsible for OOM reporting when null is returned. 40 * - template <typename T> T* pod_calloc(size_t) 41 * Responsible for OOM reporting when null is returned. 42 * - template <typename T> T* pod_realloc(T*, size_t, size_t) 43 * Responsible for OOM reporting when null is returned. The old allocation 44 * size is passed in, in addition to the new allocation size requested. 45 * - template <typename T> void free_(T*, size_t) 46 * The capacity passed in must match the old allocation size. 47 * - template <typename T> void free_(T*) 48 * Frees a buffer without knowing its allocated size. This might not be 49 * implemented by allocation policies that need the allocation size. 50 * - void reportAllocOverflow() const 51 * Called on allocation overflow (that is, an allocation implicitly tried 52 * to allocate more than the available memory space -- think allocating an 53 * array of large-size objects, where N * size overflows) before null is 54 * returned. 55 * - bool checkSimulatedOOM() const 56 * Some clients generally allocate memory yet in some circumstances won't 57 * need to do so. For example, appending to a vector with a small amount of 58 * inline storage generally allocates memory, but no allocation occurs 59 * unless appending exceeds inline storage. But for testing purposes, it 60 * can be useful to treat *every* operation as allocating. 61 * Clients (such as this hypothetical append method implementation) should 62 * call this method in situations that don't allocate, but could generally, 63 * to support this. The default behavior should return true; more 64 * complicated behavior might be to return false only after a certain 65 * number of allocations-or-check-simulated-OOMs (coordinating with the 66 * other AllocPolicy methods) have occurred. 67 * 68 * mfbt provides (and typically uses by default) only MallocAllocPolicy, which 69 * does nothing more than delegate to the malloc/alloc/free functions. 70 */ 71 72 /* 73 * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no 74 * extra behaviors. 75 */ 76 class MallocAllocPolicy { 77 public: 78 template <typename T> 79 T* maybe_pod_malloc(size_t aNumElems) { 80 size_t size; 81 if (MOZ_UNLIKELY(!mozilla::SafeMul(aNumElems, sizeof(T), &size))) 82 return nullptr; 83 return static_cast<T*>(malloc(size)); 84 } 85 86 template <typename T> 87 T* maybe_pod_calloc(size_t aNumElems) { 88 return static_cast<T*>(calloc(aNumElems, sizeof(T))); 89 } 90 91 template <typename T> 92 T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { 93 size_t size; 94 if (MOZ_UNLIKELY(!mozilla::SafeMul(aNewSize, sizeof(T), &size))) 95 return nullptr; 96 return static_cast<T*>(realloc(aPtr, size)); 97 } 98 99 template <typename T> 100 T* pod_malloc(size_t aNumElems) { 101 return maybe_pod_malloc<T>(aNumElems); 102 } 103 104 template <typename T> 105 T* pod_calloc(size_t aNumElems) { 106 return maybe_pod_calloc<T>(aNumElems); 107 } 108 109 template <typename T> 110 T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { 111 return maybe_pod_realloc<T>(aPtr, aOldSize, aNewSize); 112 } 113 114 template <typename T> 115 void free_(T* aPtr, size_t aNumElems = 0) { 116 free(aPtr); 117 } 118 119 void reportAllocOverflow() const {} 120 121 [[nodiscard]] bool checkSimulatedOOM() const { return true; } 122 }; 123 124 /* 125 * A policy which always fails to allocate memory, returning nullptr. Methods 126 * which expect an existing allocation assert. 127 * 128 * This type should be used in situations where you want to use a MFBT type with 129 * inline storage, and don't want to allow it to allocate on the heap. 130 */ 131 class NeverAllocPolicy { 132 public: 133 template <typename T> 134 T* maybe_pod_malloc(size_t aNumElems) { 135 return nullptr; 136 } 137 138 template <typename T> 139 T* maybe_pod_calloc(size_t aNumElems) { 140 return nullptr; 141 } 142 143 template <typename T> 144 T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { 145 MOZ_CRASH("NeverAllocPolicy::maybe_pod_realloc"); 146 } 147 148 template <typename T> 149 T* pod_malloc(size_t aNumElems) { 150 return nullptr; 151 } 152 153 template <typename T> 154 T* pod_calloc(size_t aNumElems) { 155 return nullptr; 156 } 157 158 template <typename T> 159 T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) { 160 MOZ_CRASH("NeverAllocPolicy::pod_realloc"); 161 } 162 163 template <typename T> 164 void free_(T* aPtr, size_t aNumElems = 0) { 165 MOZ_CRASH("NeverAllocPolicy::free_"); 166 } 167 168 void reportAllocOverflow() const {} 169 170 [[nodiscard]] bool checkSimulatedOOM() const { return true; } 171 }; 172 173 } // namespace mozilla 174 175 #endif /* mozilla_AllocPolicy_h */