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