10c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//===-- sanitizer_common_libcdep.cc ---------------------------------------===//
20c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//
30c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//                     The LLVM Compiler Infrastructure
40c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//
50c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne// This file is distributed under the University of Illinois Open Source
60c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne// License. See LICENSE.TXT for details.
70c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//
80c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//===----------------------------------------------------------------------===//
90c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//
100c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne// This file is shared between AddressSanitizer and ThreadSanitizer
110c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne// run-time libraries.
120c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne//===----------------------------------------------------------------------===//
130c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne
140c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne#include "sanitizer_common.h"
15799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
162d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines#include "sanitizer_flags.h"
1786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines#include "sanitizer_stackdepot.h"
186d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_stacktrace.h"
196d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_symbolizer.h"
200c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne
21259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar#if SANITIZER_POSIX
22259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar#include "sanitizer_posix.h"
23259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar#endif
24259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar
250c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbournenamespace __sanitizer {
260c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne
27259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainarbool ReportFile::SupportsColors() {
2886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SpinMutexLock l(mu);
2986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  ReopenIfNecessary();
30259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar  return SupportsColoredOutput(fd);
310c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne}
320c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne
3386277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesbool ColorizeReports() {
34650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev  // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
35650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev  // printing on Windows.
36650c7d44b659ddfb4af471dc2ad79a727b7de939Sergey Matveev  if (SANITIZER_WINDOWS)
3786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    return false;
382d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
392d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  const char *flag = common_flags()->color;
402d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  return internal_strcmp(flag, "always") == 0 ||
41259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar         (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
422d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
432d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
442d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesstatic void (*sandboxing_callback)();
452d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid SetSandboxingCallback(void (*f)()) {
462d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  sandboxing_callback = f;
472d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
482d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
496d1862363c88c183b0ed7740fca876342cf0474bStephen Hinesvoid ReportErrorSummary(const char *error_type, StackTrace *stack) {
50799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#if !SANITIZER_GO
516d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  if (!common_flags()->print_summary)
526d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    return;
537c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  if (stack->size == 0) {
547c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    ReportErrorSummary(error_type);
557c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar    return;
566d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  }
577c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // Currently, we include the first stack frame into the report summary.
587c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
597c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
607c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
617c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  ReportErrorSummary(error_type, frame->info);
627c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar  frame->ClearAll();
63799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#endif
6486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
6586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
6686277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesstatic void (*SoftRssLimitExceededCallback)(bool exceeded);
6786277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
6886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
6986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  SoftRssLimitExceededCallback = Callback;
7086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
7186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
7286277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid BackgroundThread(void *arg) {
7386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
7486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
7586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  uptr prev_reported_rss = 0;
7686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  uptr prev_reported_stack_depot_size = 0;
7786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  bool reached_soft_rss_limit = false;
7886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  while (true) {
7986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    SleepForMillis(100);
8086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    uptr current_rss_mb = GetRSS() >> 20;
8186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if (Verbosity()) {
8286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      // If RSS has grown 10% since last time, print some information.
8386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      if (prev_reported_rss * 11 / 10 < current_rss_mb) {
8486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
8586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        prev_reported_rss = current_rss_mb;
8686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      }
8786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      // If stack depot has grown 10% since last time, print it too.
8886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      StackDepotStats *stack_depot_stats = StackDepotGetStats();
8986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      if (prev_reported_stack_depot_size * 11 / 10 <
9086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines          stack_depot_stats->allocated) {
9186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
9286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines               SanitizerToolName,
9386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines               stack_depot_stats->n_uniq_ids,
9486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines               stack_depot_stats->allocated >> 20);
9586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        prev_reported_stack_depot_size = stack_depot_stats->allocated;
9686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      }
9786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    }
9886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    // Check RSS against the limit.
9986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
10086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
10186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines             SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
10286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      DumpProcessMap();
10386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      Die();
10486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    }
10586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    if (soft_rss_limit_mb) {
10686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
10786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        reached_soft_rss_limit = true;
10886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
10986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines               SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
11086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        if (SoftRssLimitExceededCallback)
11186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines          SoftRssLimitExceededCallback(true);
11286277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      } else if (soft_rss_limit_mb >= current_rss_mb &&
11386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines                 reached_soft_rss_limit) {
11486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        reached_soft_rss_limit = false;
11586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines        if (SoftRssLimitExceededCallback)
11686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines          SoftRssLimitExceededCallback(false);
11786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      }
11886277eb844c4983c81de62d7c050e92fe7155788Stephen Hines    }
11986277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  }
12086277eb844c4983c81de62d7c050e92fe7155788Stephen Hines}
12186277eb844c4983c81de62d7c050e92fe7155788Stephen Hines
122799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainarvoid WriteToSyslog(const char *msg) {
123799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  InternalScopedString msg_copy(kErrorMessageBufferSize);
124799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  msg_copy.append("%s", msg);
125799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  char *p = msg_copy.data();
126799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  char *q;
127799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
128799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  // Print one line at a time.
129799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  // syslog, at least on Android, has an implicit message length limit.
130799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  do {
131799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    q = internal_strchr(p, '\n');
132799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    if (q)
133799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar      *q = '\0';
134799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    WriteOneLineToSyslog(p);
135799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    if (q)
136799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar      p = q + 1;
137799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  } while (q);
138799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar}
139799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
14086277eb844c4983c81de62d7c050e92fe7155788Stephen Hinesvoid MaybeStartBackgroudThread() {
141799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar#if SANITIZER_LINUX && \
142799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    !SANITIZER_GO  // Need to implement/test on other platforms.
14386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  // Start the background thread if one of the rss limits is given.
14486277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (!common_flags()->hard_rss_limit_mb &&
14586277eb844c4983c81de62d7c050e92fe7155788Stephen Hines      !common_flags()->soft_rss_limit_mb) return;
14686277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (!&real_pthread_create) return;  // Can't spawn the thread anyway.
14786277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  internal_start_thread(BackgroundThread, nullptr);
148259f7063e3e4c4b94dded1e90ab0a943d0fa737bPirama Arumuga Nainar#endif
1496d1862363c88c183b0ed7740fca876342cf0474bStephen Hines}
1506d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
1510c547de62dc0852a03fae2d868fa571e7f5512b3Peter Collingbourne}  // namespace __sanitizer
1522d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines
1532d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hinesvoid NOINLINE
1542d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
1552d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  PrepareForSandboxing(args);
1562d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines  if (sandboxing_callback)
1572d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines    sandboxing_callback();
1582d1fdb26e458c4ddc04155c1d421bced3ba90cd0Stephen Hines}
159