Home | History | Annotate | Download | only in process
      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