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