sanitizer_common_libcdep.cc revision 1.3
1//===-- sanitizer_common_libcdep.cc ---------------------------------------===//
2//
3// This file is distributed under the University of Illinois Open Source
4// License. See LICENSE.TXT for details.
5//
6//===----------------------------------------------------------------------===//
7//
8// This file is shared between AddressSanitizer and ThreadSanitizer
9// run-time libraries.
10//===----------------------------------------------------------------------===//
11
12#include "sanitizer_common.h"
13
14#include "sanitizer_allocator_interface.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
24namespace __sanitizer {
25
26bool ReportFile::SupportsColors() {
27  SpinMutexLock l(mu);
28  ReopenIfNecessary();
29  return SupportsColoredOutput(fd);
30}
31
32bool 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
43static void (*sandboxing_callback)();
44void SetSandboxingCallback(void (*f)()) {
45  sandboxing_callback = f;
46}
47
48void ReportErrorSummary(const char *error_type, const StackTrace *stack) {
49#if !SANITIZER_GO
50  if (!common_flags()->print_summary)
51    return;
52  if (stack->size == 0) {
53    ReportErrorSummary(error_type);
54    return;
55  }
56  // Currently, we include the first stack frame into the report summary.
57  // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
58  uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
59  SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
60  ReportErrorSummary(error_type, frame->info);
61  frame->ClearAll();
62#endif
63}
64
65static void (*SoftRssLimitExceededCallback)(bool exceeded);
66void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
67  CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
68  SoftRssLimitExceededCallback = Callback;
69}
70
71static AllocatorReleaseToOSCallback ReleseCallback;
72void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback) {
73  CHECK_EQ(ReleseCallback, nullptr);
74  ReleseCallback = Callback;
75}
76
77#if SANITIZER_LINUX && !SANITIZER_GO
78void BackgroundThread(void *arg) {
79  uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
80  uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
81  bool heap_profile = common_flags()->heap_profile;
82  bool allocator_release_to_os = common_flags()->allocator_release_to_os;
83  uptr prev_reported_rss = 0;
84  uptr prev_reported_stack_depot_size = 0;
85  bool reached_soft_rss_limit = false;
86  uptr rss_during_last_reported_profile = 0;
87  while (true) {
88    SleepForMillis(100);
89    uptr current_rss_mb = GetRSS() >> 20;
90    if (Verbosity()) {
91      // If RSS has grown 10% since last time, print some information.
92      if (prev_reported_rss * 11 / 10 < current_rss_mb) {
93        Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
94        prev_reported_rss = current_rss_mb;
95      }
96      // If stack depot has grown 10% since last time, print it too.
97      StackDepotStats *stack_depot_stats = StackDepotGetStats();
98      if (prev_reported_stack_depot_size * 11 / 10 <
99          stack_depot_stats->allocated) {
100        Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
101               SanitizerToolName,
102               stack_depot_stats->n_uniq_ids,
103               stack_depot_stats->allocated >> 20);
104        prev_reported_stack_depot_size = stack_depot_stats->allocated;
105      }
106    }
107    // Check RSS against the limit.
108    if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
109      Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
110             SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
111      DumpProcessMap();
112      Die();
113    }
114    if (soft_rss_limit_mb) {
115      if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
116        reached_soft_rss_limit = true;
117        Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
118               SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
119        if (SoftRssLimitExceededCallback)
120          SoftRssLimitExceededCallback(true);
121      } else if (soft_rss_limit_mb >= current_rss_mb &&
122                 reached_soft_rss_limit) {
123        reached_soft_rss_limit = false;
124        if (SoftRssLimitExceededCallback)
125          SoftRssLimitExceededCallback(false);
126      }
127    }
128    if (allocator_release_to_os && ReleseCallback) ReleseCallback();
129    if (heap_profile &&
130        current_rss_mb > rss_during_last_reported_profile * 1.1) {
131      Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
132      __sanitizer_print_memory_profile(90);
133      rss_during_last_reported_profile = current_rss_mb;
134    }
135  }
136}
137#endif
138
139void WriteToSyslog(const char *msg) {
140  InternalScopedString msg_copy(kErrorMessageBufferSize);
141  msg_copy.append("%s", msg);
142  char *p = msg_copy.data();
143  char *q;
144
145  // Print one line at a time.
146  // syslog, at least on Android, has an implicit message length limit.
147  do {
148    q = internal_strchr(p, '\n');
149    if (q)
150      *q = '\0';
151    WriteOneLineToSyslog(p);
152    if (q)
153      p = q + 1;
154  } while (q);
155}
156
157void MaybeStartBackgroudThread() {
158#if SANITIZER_LINUX && \
159    !SANITIZER_GO  // Need to implement/test on other platforms.
160  // Start the background thread if one of the rss limits is given.
161  if (!common_flags()->hard_rss_limit_mb &&
162      !common_flags()->soft_rss_limit_mb &&
163      !common_flags()->allocator_release_to_os &&
164      !common_flags()->heap_profile) return;
165  if (!&real_pthread_create) return;  // Can't spawn the thread anyway.
166  internal_start_thread(BackgroundThread, nullptr);
167#endif
168}
169
170}  // namespace __sanitizer
171
172void NOINLINE
173__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
174  __sanitizer::PrepareForSandboxing(args);
175  if (__sanitizer::sandboxing_callback)
176    __sanitizer::sandboxing_callback();
177}
178