1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 <stddef.h> 8 9 #include <new> 10 11 #include "base/allocator/allocator_shim.h" 12 #include "base/allocator/buildflags.h" 13 #include "base/files/file_path.h" 14 #include "base/files/file_util.h" 15 #include "base/logging.h" 16 #include "base/process/internal_linux.h" 17 #include "base/strings/string_number_conversions.h" 18 #include "build/build_config.h" 19 20 #if defined(USE_TCMALLOC) 21 #include "third_party/tcmalloc/gperftools-2.0/chromium/src/config.h" 22 #include "third_party/tcmalloc/gperftools-2.0/chromium/src/gperftools/tcmalloc.h" 23 #endif 24 25 extern "C" { 26 void* __libc_malloc(size_t size); 27 } 28 29 namespace base { 30 31 size_t g_oom_size = 0U; 32 33 namespace { 34 35 void OnNoMemorySize(size_t size) { 36 g_oom_size = size; 37 38 if (size != 0) 39 LOG(FATAL) << "Out of memory, size = " << size; 40 LOG(FATAL) << "Out of memory."; 41 } 42 43 void OnNoMemory() { 44 OnNoMemorySize(0); 45 } 46 47 } // namespace 48 49 void EnableTerminationOnHeapCorruption() { 50 // On Linux, there nothing to do AFAIK. 51 } 52 53 void EnableTerminationOnOutOfMemory() { 54 // Set the new-out of memory handler. 55 std::set_new_handler(&OnNoMemory); 56 // If we're using glibc's allocator, the above functions will override 57 // malloc and friends and make them die on out of memory. 58 59 #if BUILDFLAG(USE_ALLOCATOR_SHIM) 60 allocator::SetCallNewHandlerOnMallocFailure(true); 61 #elif defined(USE_TCMALLOC) 62 // For tcmalloc, we need to tell it to behave like new. 63 tc_set_new_mode(1); 64 #endif 65 } 66 67 // NOTE: This is not the only version of this function in the source: 68 // the setuid sandbox (in process_util_linux.c, in the sandbox source) 69 // also has its own C version. 70 bool AdjustOOMScore(ProcessId process, int score) { 71 if (score < 0 || score > kMaxOomScore) 72 return false; 73 74 FilePath oom_path(internal::GetProcPidDir(process)); 75 76 // Attempt to write the newer oom_score_adj file first. 77 FilePath oom_file = oom_path.AppendASCII("oom_score_adj"); 78 if (PathExists(oom_file)) { 79 std::string score_str = IntToString(score); 80 DVLOG(1) << "Adjusting oom_score_adj of " << process << " to " 81 << score_str; 82 int score_len = static_cast<int>(score_str.length()); 83 return (score_len == WriteFile(oom_file, score_str.c_str(), score_len)); 84 } 85 86 // If the oom_score_adj file doesn't exist, then we write the old 87 // style file and translate the oom_adj score to the range 0-15. 88 oom_file = oom_path.AppendASCII("oom_adj"); 89 if (PathExists(oom_file)) { 90 // Max score for the old oom_adj range. Used for conversion of new 91 // values to old values. 92 const int kMaxOldOomScore = 15; 93 94 int converted_score = score * kMaxOldOomScore / kMaxOomScore; 95 std::string score_str = IntToString(converted_score); 96 DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str; 97 int score_len = static_cast<int>(score_str.length()); 98 return (score_len == WriteFile(oom_file, score_str.c_str(), score_len)); 99 } 100 101 return false; 102 } 103 104 bool UncheckedMalloc(size_t size, void** result) { 105 #if BUILDFLAG(USE_ALLOCATOR_SHIM) 106 *result = allocator::UncheckedAlloc(size); 107 #elif defined(MEMORY_TOOL_REPLACES_ALLOCATOR) || \ 108 (!defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)) 109 *result = malloc(size); 110 #elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC) 111 *result = __libc_malloc(size); 112 #elif defined(USE_TCMALLOC) 113 *result = tc_malloc_skip_new_handler(size); 114 #endif 115 return *result != nullptr; 116 } 117 118 } // namespace base 119