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