summaryrefslogtreecommitdiffstats
path: root/mfbt/AllocPolicy.h
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /mfbt/AllocPolicy.h
parentInitial commit. (diff)
downloadthunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.tar.xz
thunderbird-6bf0a5cb5034a7e684dcc3500e841785237ce2dd.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'mfbt/AllocPolicy.h')
-rw-r--r--mfbt/AllocPolicy.h175
1 files changed, 175 insertions, 0 deletions
diff --git a/mfbt/AllocPolicy.h b/mfbt/AllocPolicy.h
new file mode 100644
index 0000000000..e5c62bcd64
--- /dev/null
+++ b/mfbt/AllocPolicy.h
@@ -0,0 +1,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 {}
+
+ [[nodiscard]] 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 {}
+
+ [[nodiscard]] bool checkSimulatedOOM() const { return true; }
+};
+
+} // namespace mozilla
+
+#endif /* mozilla_AllocPolicy_h */