Line data Source code
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/Attributes.h"
16 : #include "mozilla/TemplateLib.h"
17 :
18 : #include <stddef.h>
19 : #include <stdlib.h>
20 :
21 : namespace mozilla {
22 :
23 : /*
24 : * Allocation policies are used to implement the standard allocation behaviors
25 : * in a customizable way. Additionally, custom behaviors may be added to these
26 : * behaviors, such as additionally reporting an error through an out-of-band
27 : * mechanism when OOM occurs. The concept modeled here is as follows:
28 : *
29 : * - public copy constructor, assignment, destructor
30 : * - template <typename T> T* maybe_pod_malloc(size_t)
31 : * Fallible, but doesn't report an error on OOM.
32 : * - template <typename T> T* maybe_pod_calloc(size_t)
33 : * Fallible, but doesn't report an error on OOM.
34 : * - template <typename T> T* maybe_pod_realloc(T*, size_t, size_t)
35 : * Fallible, but doesn't report an error on OOM. The old allocation
36 : * size is passed in, in addition to the new allocation size requested.
37 : * - template <typename T> T* pod_malloc(size_t)
38 : * Responsible for OOM reporting when null is returned.
39 : * - template <typename T> T* pod_calloc(size_t)
40 : * Responsible for OOM reporting when null is returned.
41 : * - template <typename T> T* pod_realloc(T*, size_t, size_t)
42 : * Responsible for OOM reporting when null is returned. The old allocation
43 : * size is passed in, in addition to the new allocation size requested.
44 : * - void free_(void*)
45 : * - void reportAllocOverflow() const
46 : * Called on allocation overflow (that is, an allocation implicitly tried
47 : * to allocate more than the available memory space -- think allocating an
48 : * array of large-size objects, where N * size overflows) before null is
49 : * returned.
50 : * - bool checkSimulatedOOM() const
51 : * Some clients generally allocate memory yet in some circumstances won't
52 : * need to do so. For example, appending to a vector with a small amount of
53 : * inline storage generally allocates memory, but no allocation occurs
54 : * unless appending exceeds inline storage. But for testing purposes, it
55 : * can be useful to treat *every* operation as allocating.
56 : * Clients (such as this hypothetical append method implementation) should
57 : * call this method in situations that don't allocate, but could generally,
58 : * to support this. The default behavior should return true; more
59 : * complicated behavior might be to return false only after a certain
60 : * number of allocations-or-check-simulated-OOMs (coordinating with the
61 : * other AllocPolicy methods) have occurred.
62 : *
63 : * mfbt provides (and typically uses by default) only MallocAllocPolicy, which
64 : * does nothing more than delegate to the malloc/alloc/free functions.
65 : */
66 :
67 : /*
68 : * A policy that straightforwardly uses malloc/calloc/realloc/free and adds no
69 : * extra behaviors.
70 : */
71 7 : class MallocAllocPolicy
72 : {
73 : public:
74 : template <typename T>
75 231 : T* maybe_pod_malloc(size_t aNumElems)
76 : {
77 101 : if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
78 0 : return nullptr;
79 : }
80 231 : return static_cast<T*>(malloc(aNumElems * sizeof(T)));
81 : }
82 :
83 : template <typename T>
84 : T* maybe_pod_calloc(size_t aNumElems)
85 : {
86 : return static_cast<T*>(calloc(aNumElems, sizeof(T)));
87 : }
88 :
89 : template <typename T>
90 712 : T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
91 : {
92 38 : if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
93 0 : return nullptr;
94 : }
95 712 : return static_cast<T*>(realloc(aPtr, aNewSize * sizeof(T)));
96 : }
97 :
98 : template <typename T>
99 231 : T* pod_malloc(size_t aNumElems)
100 : {
101 231 : return maybe_pod_malloc<T>(aNumElems);
102 : }
103 :
104 : template <typename T>
105 : T* pod_calloc(size_t aNumElems)
106 : {
107 : return maybe_pod_calloc<T>(aNumElems);
108 : }
109 :
110 : template <typename T>
111 689 : T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
112 : {
113 689 : return maybe_pod_realloc<T>(aPtr, aOldSize, aNewSize);
114 : }
115 :
116 1302 : void free_(void* aPtr)
117 : {
118 1302 : free(aPtr);
119 1302 : }
120 :
121 0 : void reportAllocOverflow() const
122 : {
123 0 : }
124 :
125 255958 : MOZ_MUST_USE bool checkSimulatedOOM() const
126 : {
127 255958 : return true;
128 : }
129 : };
130 :
131 : } // namespace mozilla
132 :
133 : #endif /* mozilla_AllocPolicy_h */
|