/work/obj-fuzz/dist/include/mozilla/CountingAllocatorBase.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef CountingAllocatorBase_h |
8 | | #define CountingAllocatorBase_h |
9 | | |
10 | | #include "mozilla/Assertions.h" |
11 | | #include "mozilla/Atomics.h" |
12 | | #include "nsIMemoryReporter.h" |
13 | | |
14 | | namespace mozilla { |
15 | | |
16 | | // This CRTP class handles several details of wrapping allocators and should |
17 | | // be preferred to manually counting with MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC |
18 | | // and MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE. The typical use is in a memory |
19 | | // reporter for a particular third party library: |
20 | | // |
21 | | // class MyMemoryReporter : public CountingAllocatorBase<MyMemoryReporter> |
22 | | // { |
23 | | // ... |
24 | | // NS_IMETHOD |
25 | | // CollectReports(nsIHandleReportCallback* aHandleReport, |
26 | | // nsISupports* aData, bool aAnonymize) override |
27 | | // { |
28 | | // MOZ_COLLECT_REPORT( |
29 | | // "explicit/path/to/somewhere", KIND_HEAP, UNITS_BYTES, |
30 | | // MemoryAllocated(), |
31 | | // "A description of what we are reporting."); |
32 | | // |
33 | | // return NS_OK; |
34 | | // } |
35 | | // }; |
36 | | // |
37 | | // ...somewhere later in the code... |
38 | | // SetThirdPartyMemoryFunctions(MyMemoryReporter::CountingAlloc, |
39 | | // MyMemoryReporter::CountingFree); |
40 | | template<typename T> |
41 | | class CountingAllocatorBase |
42 | | { |
43 | | public: |
44 | | CountingAllocatorBase() |
45 | 6 | { |
46 | | #ifdef DEBUG |
47 | | // There must be only one instance of this class, due to |sAmount| being |
48 | | // static. |
49 | | static bool hasRun = false; |
50 | | MOZ_ASSERT(!hasRun); |
51 | | hasRun = true; |
52 | | #endif |
53 | | } mozilla::CountingAllocatorBase<ICUReporter>::CountingAllocatorBase() Line | Count | Source | 45 | 3 | { | 46 | | #ifdef DEBUG | 47 | | // There must be only one instance of this class, due to |sAmount| being | 48 | | // static. | 49 | | static bool hasRun = false; | 50 | | MOZ_ASSERT(!hasRun); | 51 | | hasRun = true; | 52 | | #endif | 53 | | } |
mozilla::CountingAllocatorBase<OggReporter>::CountingAllocatorBase() Line | Count | Source | 45 | 3 | { | 46 | | #ifdef DEBUG | 47 | | // There must be only one instance of this class, due to |sAmount| being | 48 | | // static. | 49 | | static bool hasRun = false; | 50 | | MOZ_ASSERT(!hasRun); | 51 | | hasRun = true; | 52 | | #endif | 53 | | } |
|
54 | | |
55 | | static size_t |
56 | | MemoryAllocated() |
57 | 0 | { |
58 | 0 | return sAmount; |
59 | 0 | } Unexecuted instantiation: mozilla::CountingAllocatorBase<ICUReporter>::MemoryAllocated() Unexecuted instantiation: mozilla::CountingAllocatorBase<OggReporter>::MemoryAllocated() Unexecuted instantiation: mozilla::CountingAllocatorBase<HunspellAllocator>::MemoryAllocated() |
60 | | |
61 | | static void* |
62 | | CountingMalloc(size_t size) |
63 | 2.52k | { |
64 | 2.52k | void* p = malloc(size); |
65 | 2.52k | sAmount += MallocSizeOfOnAlloc(p); |
66 | 2.52k | return p; |
67 | 2.52k | } mozilla::CountingAllocatorBase<ICUReporter>::CountingMalloc(unsigned long) Line | Count | Source | 63 | 2.52k | { | 64 | 2.52k | void* p = malloc(size); | 65 | 2.52k | sAmount += MallocSizeOfOnAlloc(p); | 66 | 2.52k | return p; | 67 | 2.52k | } |
Unexecuted instantiation: mozilla::CountingAllocatorBase<OggReporter>::CountingMalloc(unsigned long) Unexecuted instantiation: mozilla::CountingAllocatorBase<HunspellAllocator>::CountingMalloc(unsigned long) |
68 | | |
69 | | static void* |
70 | | CountingCalloc(size_t nmemb, size_t size) |
71 | 0 | { |
72 | 0 | void* p = calloc(nmemb, size); |
73 | 0 | sAmount += MallocSizeOfOnAlloc(p); |
74 | 0 | return p; |
75 | 0 | } Unexecuted instantiation: mozilla::CountingAllocatorBase<OggReporter>::CountingCalloc(unsigned long, unsigned long) Unexecuted instantiation: mozilla::CountingAllocatorBase<HunspellAllocator>::CountingCalloc(unsigned long, unsigned long) |
76 | | |
77 | | static void* |
78 | | CountingRealloc(void* p, size_t size) |
79 | 0 | { |
80 | 0 | size_t oldsize = MallocSizeOfOnFree(p); |
81 | 0 | void *pnew = realloc(p, size); |
82 | 0 | if (pnew) { |
83 | 0 | size_t newsize = MallocSizeOfOnAlloc(pnew); |
84 | 0 | sAmount += newsize - oldsize; |
85 | 0 | } else if (size == 0) { |
86 | 0 | // We asked for a 0-sized (re)allocation of some existing pointer |
87 | 0 | // and received NULL in return. 0-sized allocations are permitted |
88 | 0 | // to either return NULL or to allocate a unique object per call (!). |
89 | 0 | // For a malloc implementation that chooses the second strategy, |
90 | 0 | // that allocation may fail (unlikely, but possible). |
91 | 0 | // |
92 | 0 | // Given a NULL return value and an allocation size of 0, then, we |
93 | 0 | // don't know if that means the original pointer was freed or if |
94 | 0 | // the allocation of the unique object failed. If the original |
95 | 0 | // pointer was freed, then we have nothing to do here. If the |
96 | 0 | // allocation of the unique object failed, the original pointer is |
97 | 0 | // still valid and we ought to undo the decrement from above. |
98 | 0 | // However, we have no way of knowing how the underlying realloc |
99 | 0 | // implementation is behaving. Assuming that the original pointer |
100 | 0 | // was freed is the safest course of action. We do, however, need |
101 | 0 | // to note that we freed memory. |
102 | 0 | sAmount -= oldsize; |
103 | 0 | } else { |
104 | 0 | // realloc failed. The amount allocated hasn't changed. |
105 | 0 | } |
106 | 0 | return pnew; |
107 | 0 | } Unexecuted instantiation: mozilla::CountingAllocatorBase<ICUReporter>::CountingRealloc(void*, unsigned long) Unexecuted instantiation: mozilla::CountingAllocatorBase<OggReporter>::CountingRealloc(void*, unsigned long) Unexecuted instantiation: mozilla::CountingAllocatorBase<HunspellAllocator>::CountingRealloc(void*, unsigned long) |
108 | | |
109 | | // Some library code expects that realloc(x, 0) will free x, which is not |
110 | | // the behavior of the version of jemalloc we're using, so this wrapped |
111 | | // version of realloc is needed. |
112 | | static void* |
113 | | CountingFreeingRealloc(void* p, size_t size) |
114 | | { |
115 | | if (size == 0) { |
116 | | CountingFree(p); |
117 | | return nullptr; |
118 | | } |
119 | | return CountingRealloc(p, size); |
120 | | } |
121 | | |
122 | | static void |
123 | | CountingFree(void* p) |
124 | 2.47k | { |
125 | 2.47k | sAmount -= MallocSizeOfOnFree(p); |
126 | 2.47k | free(p); |
127 | 2.47k | } mozilla::CountingAllocatorBase<ICUReporter>::CountingFree(void*) Line | Count | Source | 124 | 2.47k | { | 125 | 2.47k | sAmount -= MallocSizeOfOnFree(p); | 126 | 2.47k | free(p); | 127 | 2.47k | } |
Unexecuted instantiation: mozilla::CountingAllocatorBase<OggReporter>::CountingFree(void*) Unexecuted instantiation: mozilla::CountingAllocatorBase<HunspellAllocator>::CountingFree(void*) |
128 | | |
129 | | private: |
130 | | // |sAmount| can be (implicitly) accessed by multiple threads, so it |
131 | | // must be thread-safe. It may be written during GC, so accesses are not |
132 | | // recorded. |
133 | | typedef Atomic<size_t, SequentiallyConsistent, recordreplay::Behavior::DontPreserve> AmountType; |
134 | | static AmountType sAmount; |
135 | | |
136 | | MOZ_DEFINE_MALLOC_SIZE_OF_ON_ALLOC(MallocSizeOfOnAlloc) |
137 | | MOZ_DEFINE_MALLOC_SIZE_OF_ON_FREE(MallocSizeOfOnFree) |
138 | | }; |
139 | | |
140 | | } // namespace mozilla |
141 | | |
142 | | #endif // CountingAllocatorBase_h |