Home | History | Annotate | 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_common.h"
     15 #include "sanitizer_flags.h"
     16 #include "sanitizer_stackdepot.h"
     17 #include "sanitizer_stacktrace.h"
     18 #include "sanitizer_symbolizer.h"
     19 
     20 #if SANITIZER_POSIX
     21 #include "sanitizer_posix.h"
     22 #endif
     23 
     24 namespace __sanitizer {
     25 
     26 bool ReportFile::SupportsColors() {
     27   SpinMutexLock l(mu);
     28   ReopenIfNecessary();
     29   return SupportsColoredOutput(fd);
     30 }
     31 
     32 bool ColorizeReports() {
     33   // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
     34   // printing on Windows.
     35   if (SANITIZER_WINDOWS)
     36     return false;
     37 
     38   const char *flag = common_flags()->color;
     39   return internal_strcmp(flag, "always") == 0 ||
     40          (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
     41 }
     42 
     43 static void (*sandboxing_callback)();
     44 void SetSandboxingCallback(void (*f)()) {
     45   sandboxing_callback = f;
     46 }
     47 
     48 void ReportErrorSummary(const char *error_type, StackTrace *stack) {
     49   if (!common_flags()->print_summary)
     50     return;
     51   if (stack->size == 0) {
     52     ReportErrorSummary(error_type);
     53     return;
     54   }
     55   // Currently, we include the first stack frame into the report summary.
     56   // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
     57   uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
     58   SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
     59   ReportErrorSummary(error_type, frame->info);
     60   frame->ClearAll();
     61 }
     62 
     63 static void (*SoftRssLimitExceededCallback)(bool exceeded);
     64 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
     65   CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
     66   SoftRssLimitExceededCallback = Callback;
     67 }
     68 
     69 void BackgroundThread(void *arg) {
     70   uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
     71   uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
     72   uptr prev_reported_rss = 0;
     73   uptr prev_reported_stack_depot_size = 0;
     74   bool reached_soft_rss_limit = false;
     75   while (true) {
     76     SleepForMillis(100);
     77     uptr current_rss_mb = GetRSS() >> 20;
     78     if (Verbosity()) {
     79       // If RSS has grown 10% since last time, print some information.
     80       if (prev_reported_rss * 11 / 10 < current_rss_mb) {
     81         Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
     82         prev_reported_rss = current_rss_mb;
     83       }
     84       // If stack depot has grown 10% since last time, print it too.
     85       StackDepotStats *stack_depot_stats = StackDepotGetStats();
     86       if (prev_reported_stack_depot_size * 11 / 10 <
     87           stack_depot_stats->allocated) {
     88         Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
     89                SanitizerToolName,
     90                stack_depot_stats->n_uniq_ids,
     91                stack_depot_stats->allocated >> 20);
     92         prev_reported_stack_depot_size = stack_depot_stats->allocated;
     93       }
     94     }
     95     // Check RSS against the limit.
     96     if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
     97       Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
     98              SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
     99       DumpProcessMap();
    100       Die();
    101     }
    102     if (soft_rss_limit_mb) {
    103       if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
    104         reached_soft_rss_limit = true;
    105         Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
    106                SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
    107         if (SoftRssLimitExceededCallback)
    108           SoftRssLimitExceededCallback(true);
    109       } else if (soft_rss_limit_mb >= current_rss_mb &&
    110                  reached_soft_rss_limit) {
    111         reached_soft_rss_limit = false;
    112         if (SoftRssLimitExceededCallback)
    113           SoftRssLimitExceededCallback(false);
    114       }
    115     }
    116   }
    117 }
    118 
    119 void MaybeStartBackgroudThread() {
    120 #if SANITIZER_LINUX  // Need to implement/test on other platforms.
    121   // Start the background thread if one of the rss limits is given.
    122   if (!common_flags()->hard_rss_limit_mb &&
    123       !common_flags()->soft_rss_limit_mb) return;
    124   if (!&real_pthread_create) return;  // Can't spawn the thread anyway.
    125   internal_start_thread(BackgroundThread, nullptr);
    126 #endif
    127 }
    128 
    129 }  // namespace __sanitizer
    130 
    131 void NOINLINE
    132 __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
    133   PrepareForSandboxing(args);
    134   if (sandboxing_callback)
    135     sandboxing_callback();
    136 }
    137