xref: /aosp_15_r20/external/cronet/base/process/memory_mac.mm (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1// Copyright 2013 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/process/memory.h"
6
7#include <stdlib.h>
8#include <new>
9
10#include "build/build_config.h"
11#include "partition_alloc/partition_alloc_buildflags.h"
12#include "partition_alloc/shim/allocator_interception_apple.h"
13#include "partition_alloc/shim/allocator_shim.h"
14
15namespace base {
16
17namespace {
18void oom_killer_new() {
19  TerminateBecauseOutOfMemory(0);
20}
21}  // namespace
22
23void EnableTerminationOnHeapCorruption() {
24#if !ARCH_CPU_64_BITS
25  DLOG(WARNING) << "EnableTerminationOnHeapCorruption only works on 64-bit";
26#endif
27}
28
29bool UncheckedMalloc(size_t size, void** result) {
30#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
31  // Unchecked allocations can happen before the default malloc() zone is
32  // registered. In this case, going straight to the shim may explode, since the
33  // memory will come from a zone which is unknown to the dispatching code in
34  // libmalloc. Meaning that if the memory gets free()-d, realloc()-ed, or its
35  // actual size is queried with malloc_size() *before* we get to register our
36  // zone, we crash.
37  //
38  // The cleanest solution would be to detect it and forbid it, but tests (at
39  // least) allocate in static constructors. Meaning that this code is
40  // sufficient to cause a crash:
41  //
42  // void* ptr = []() {
43  //  void* ptr;
44  //  bool ok = base::UncheckedMalloc(1000, &ptr);
45  //  CHECK(ok);
46  //  free(ptr);
47  // }();
48  //
49  // (Our static initializer is supposed to have priority, but it doesn't seem
50  // to work in practice, at least for MachO).
51  //
52  // Since unchecked allocations are rare, let's err on the side of caution.
53  if (!allocator_shim::IsDefaultAllocatorPartitionRootInitialized()) {
54    *result = malloc(size);
55    return *result != nullptr;
56  }
57
58  // Unlike use_partition_alloc_as_malloc=false, the default malloc zone is
59  // replaced with PartitionAlloc, so the allocator shim functions work best.
60  *result = allocator_shim::UncheckedAlloc(size);
61  return *result != nullptr;
62#elif BUILDFLAG(USE_ALLOCATOR_SHIM)
63  return allocator_shim::UncheckedMallocMac(size, result);
64#else   // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
65        // !BUILDFLAG(USE_ALLOCATOR_SHIM)
66  *result = malloc(size);
67  return *result != nullptr;
68#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) &&
69        // !BUILDFLAG(USE_ALLOCATOR_SHIM)
70}
71
72// The standard version is defined in memory.cc in case of
73// USE_PARTITION_ALLOC_AS_MALLOC.
74#if !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
75bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
76#if BUILDFLAG(USE_ALLOCATOR_SHIM)
77  return allocator_shim::UncheckedCallocMac(num_items, size, result);
78#else
79  *result = calloc(num_items, size);
80  return *result != nullptr;
81#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM)
82}
83#endif  // !BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
84
85void EnableTerminationOnOutOfMemory() {
86  // Step 1: Enable OOM killer on C++ failures.
87  std::set_new_handler(oom_killer_new);
88
89// Step 2: Enable OOM killer on C-malloc failures for the default zone (if we
90// have a shim).
91#if BUILDFLAG(USE_ALLOCATOR_SHIM)
92  allocator_shim::SetCallNewHandlerOnMallocFailure(true);
93
94  // Step 3: Enable OOM killer on all other malloc zones (or just "all" without
95  // "other" if shim is disabled).
96  allocator_shim::InterceptAllocationsMac();
97#endif  // BUILDFLAG(USE_ALLOCATOR_SHIM)
98}
99
100void UncheckedFree(void* ptr) {
101#if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
102  // Important: might be different from free(), because in some cases, free()
103  // does not necessarily know about allocator_shim::* functions.
104  allocator_shim::UncheckedFree(ptr);
105#else   // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
106  free(ptr);
107#endif  // BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
108}
109
110}  // namespace base
111