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
OnNoMemorySize(size_t size)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
OnNoMemory()43 void OnNoMemory() {
44 OnNoMemorySize(0);
45 }
46
47 } // namespace
48
EnableTerminationOnHeapCorruption()49 void EnableTerminationOnHeapCorruption() {
50 // On Linux, there nothing to do AFAIK.
51 }
52
EnableTerminationOnOutOfMemory()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.
AdjustOOMScore(ProcessId process,int score)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
UncheckedMalloc(size_t size,void ** result)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