Home | History | Annotate | Line # | Download | only in sanitizer_common
      1 //===-- sanitizer_common_libcdep.cc ---------------------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file is shared between AddressSanitizer and ThreadSanitizer
     11 // run-time libraries.
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "sanitizer_allocator_interface.h"
     15 #include "sanitizer_common.h"
     16 #include "sanitizer_flags.h"
     17 #include "sanitizer_procmaps.h"
     18 
     19 
     20 namespace __sanitizer {
     21 
     22 static void (*SoftRssLimitExceededCallback)(bool exceeded);
     23 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
     24   CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
     25   SoftRssLimitExceededCallback = Callback;
     26 }
     27 
     28 #if (SANITIZER_LINUX || SANITIZER_NETBSD) && !SANITIZER_GO
     29 // Weak default implementation for when sanitizer_stackdepot is not linked in.
     30 SANITIZER_WEAK_ATTRIBUTE StackDepotStats *StackDepotGetStats() {
     31   return nullptr;
     32 }
     33 
     34 void BackgroundThread(void *arg) {
     35   const uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
     36   const uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
     37   const bool heap_profile = common_flags()->heap_profile;
     38   uptr prev_reported_rss = 0;
     39   uptr prev_reported_stack_depot_size = 0;
     40   bool reached_soft_rss_limit = false;
     41   uptr rss_during_last_reported_profile = 0;
     42   while (true) {
     43     SleepForMillis(100);
     44     const uptr current_rss_mb = GetRSS() >> 20;
     45     if (Verbosity()) {
     46       // If RSS has grown 10% since last time, print some information.
     47       if (prev_reported_rss * 11 / 10 < current_rss_mb) {
     48         Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
     49         prev_reported_rss = current_rss_mb;
     50       }
     51       // If stack depot has grown 10% since last time, print it too.
     52       StackDepotStats *stack_depot_stats = StackDepotGetStats();
     53       if (stack_depot_stats) {
     54         if (prev_reported_stack_depot_size * 11 / 10 <
     55             stack_depot_stats->allocated) {
     56           Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
     57                  SanitizerToolName,
     58                  stack_depot_stats->n_uniq_ids,
     59                  stack_depot_stats->allocated >> 20);
     60           prev_reported_stack_depot_size = stack_depot_stats->allocated;
     61         }
     62       }
     63     }
     64     // Check RSS against the limit.
     65     if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
     66       Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
     67              SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
     68       DumpProcessMap();
     69       Die();
     70     }
     71     if (soft_rss_limit_mb) {
     72       if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
     73         reached_soft_rss_limit = true;
     74         Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
     75                SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
     76         if (SoftRssLimitExceededCallback)
     77           SoftRssLimitExceededCallback(true);
     78       } else if (soft_rss_limit_mb >= current_rss_mb &&
     79                  reached_soft_rss_limit) {
     80         reached_soft_rss_limit = false;
     81         if (SoftRssLimitExceededCallback)
     82           SoftRssLimitExceededCallback(false);
     83       }
     84     }
     85     if (heap_profile &&
     86         current_rss_mb > rss_during_last_reported_profile * 1.1) {
     87       Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
     88       __sanitizer_print_memory_profile(90, 20);
     89       rss_during_last_reported_profile = current_rss_mb;
     90     }
     91   }
     92 }
     93 #endif
     94 
     95 void WriteToSyslog(const char *msg) {
     96   InternalScopedString msg_copy(kErrorMessageBufferSize);
     97   msg_copy.append("%s", msg);
     98   char *p = msg_copy.data();
     99   char *q;
    100 
    101   // Print one line at a time.
    102   // syslog, at least on Android, has an implicit message length limit.
    103   while ((q = internal_strchr(p, '\n'))) {
    104     *q = '\0';
    105     WriteOneLineToSyslog(p);
    106     p = q + 1;
    107   }
    108   // Print remaining characters, if there are any.
    109   // Note that this will add an extra newline at the end.
    110   // FIXME: buffer extra output. This would need a thread-local buffer, which
    111   // on Android requires plugging into the tools (ex. ASan's) Thread class.
    112   if (*p)
    113     WriteOneLineToSyslog(p);
    114 }
    115 
    116 void MaybeStartBackgroudThread() {
    117 #if (SANITIZER_LINUX || SANITIZER_NETBSD) && \
    118     !SANITIZER_GO  // Need to implement/test on other platforms.
    119   // Start the background thread if one of the rss limits is given.
    120   if (!common_flags()->hard_rss_limit_mb &&
    121       !common_flags()->soft_rss_limit_mb &&
    122       !common_flags()->heap_profile) return;
    123   if (!&real_pthread_create) return;  // Can't spawn the thread anyway.
    124   internal_start_thread(BackgroundThread, nullptr);
    125 #endif
    126 }
    127 
    128 static void (*sandboxing_callback)();
    129 void SetSandboxingCallback(void (*f)()) {
    130   sandboxing_callback = f;
    131 }
    132 
    133 }  // namespace __sanitizer
    134 
    135 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
    136                              __sanitizer_sandbox_arguments *args) {
    137   __sanitizer::PlatformPrepareForSandboxing(args);
    138   if (__sanitizer::sandboxing_callback)
    139     __sanitizer::sandboxing_callback();
    140 }
    141