tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 */