DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (69ac304560c9)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * An allocation policy concept, usable for structures and algorithms to
 * control how memory is allocated and how failures are handled.
 */

#ifndef mozilla_AllocPolicy_h
#define mozilla_AllocPolicy_h

#include "mozilla/Attributes.h"
#include "mozilla/Assertions.h"
#include "mozilla/TemplateLib.h"

#include <stddef.h>
#include <stdlib.h>

namespace mozilla {

/*
 * Allocation policies are used to implement the standard allocation behaviors
 * in a customizable way.  Additionally, custom behaviors may be added to these
 * behaviors, such as additionally reporting an error through an out-of-band
 * mechanism when OOM occurs.  The concept modeled here is as follows:
 *
 *  - public copy constructor, assignment, destructor
 *  - template <typename T> T* maybe_pod_malloc(size_t)
 *      Fallible, but doesn't report an error on OOM.
 *  - template <typename T> T* maybe_pod_calloc(size_t)
 *      Fallible, but doesn't report an error on OOM.
 *  - template <typename T> T* maybe_pod_realloc(T*, size_t, size_t)
 *      Fallible, but doesn't report an error on OOM.  The old allocation
 *      size is passed in, in addition to the new allocation size requested.
 *  - template <typename T> T* pod_malloc(size_t)
 *      Responsible for OOM reporting when null is returned.
 *  - template <typename T> T* pod_calloc(size_t)
 *      Responsible for OOM reporting when null is returned.
 *  - template <typename T> T* pod_realloc(T*, size_t, size_t)
 *      Responsible for OOM reporting when null is returned.  The old allocation
 *      size is passed in, in addition to the new allocation size requested.
 *  - template <typename T> void free_(T*, size_t)
 *      The capacity passed in must match the old allocation size.
 *  - template <typename T> void free_(T*)
 *      Frees a buffer without knowing its allocated size. This might not be
 *      implemented by allocation policies that need the allocation size.
 *  - void reportAllocOverflow() const
 *      Called on allocation overflow (that is, an allocation implicitly tried
 *      to allocate more than the available memory space -- think allocating an
 *      array of large-size objects, where N * size overflows) before null is
 *      returned.
 *  - bool checkSimulatedOOM() const
 *      Some clients generally allocate memory yet in some circumstances won't
 *      need to do so. For example, appending to a vector with a small amount of
 *      inline storage generally allocates memory, but no allocation occurs
 *      unless appending exceeds inline storage. But for testing purposes, it
 *      can be useful to treat *every* operation as allocating.
 *      Clients (such as this hypothetical append method implementation) should
 *      call this method in situations that don't allocate, but could generally,
 *      to support this. The default behavior should return true; more
 *      complicated behavior might be to return false only after a certain
 *      number of allocations-or-check-simulated-OOMs (coordinating with the
 *      other AllocPolicy methods) have occurred.
 *
 * mfbt provides (and typically uses by default) only MallocAllocPolicy, which
 * does nothing more than delegate to the malloc/alloc/free functions.
 */

/*
 * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no
 * extra behaviors.
 */
class MallocAllocPolicy {
 public:
  template <typename T>
  T* maybe_pod_malloc(size_t aNumElems) {
    if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
      return nullptr;
    }
    return static_cast<T*>(malloc(aNumElems * sizeof(T)));
  }

  template <typename T>
  T* maybe_pod_calloc(size_t aNumElems) {
    return static_cast<T*>(calloc(aNumElems, sizeof(T)));
  }

  template <typename T>
  T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
    if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
      return nullptr;
    }
    return static_cast<T*>(realloc(aPtr, aNewSize * sizeof(T)));
  }

  template <typename T>
  T* pod_malloc(size_t aNumElems) {
    return maybe_pod_malloc<T>(aNumElems);
  }

  template <typename T>
  T* pod_calloc(size_t aNumElems) {
    return maybe_pod_calloc<T>(aNumElems);
  }

  template <typename T>
  T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
    return maybe_pod_realloc<T>(aPtr, aOldSize, aNewSize);
  }

  template <typename T>
  void free_(T* aPtr, size_t aNumElems = 0) {
    free(aPtr);
  }

  void reportAllocOverflow() const {}

  MOZ_MUST_USE bool checkSimulatedOOM() const { return true; }
};

/*
 * A policy which always fails to allocate memory, returning nullptr. Methods
 * which expect an existing allocation assert.
 *
 * This type should be used in situations where you want to use a MFBT type with
 * inline storage, and don't want to allow it to allocate on the heap.
 */
class NeverAllocPolicy {
 public:
  template <typename T>
  T* maybe_pod_malloc(size_t aNumElems) {
    return nullptr;
  }

  template <typename T>
  T* maybe_pod_calloc(size_t aNumElems) {
    return nullptr;
  }

  template <typename T>
  T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
    MOZ_CRASH("NeverAllocPolicy::maybe_pod_realloc");
  }

  template <typename T>
  T* pod_malloc(size_t aNumElems) {
    return nullptr;
  }

  template <typename T>
  T* pod_calloc(size_t aNumElems) {
    return nullptr;
  }

  template <typename T>
  T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
    MOZ_CRASH("NeverAllocPolicy::pod_realloc");
  }

  template <typename T>
  void free_(T* aPtr, size_t aNumElems = 0) {
    MOZ_CRASH("NeverAllocPolicy::free_");
  }

  void reportAllocOverflow() const {}

  MOZ_MUST_USE bool checkSimulatedOOM() const { return true; }
};

}  // namespace mozilla

#endif /* mozilla_AllocPolicy_h */