* function.c (dump_stack_clash_frame_info): New function.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_common_libcdep.cc
blob8c9fa98f835f4aa4ee1f284f2f73d403fe758453
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 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common.h"
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"
20 #if SANITIZER_POSIX
21 #include "sanitizer_posix.h"
22 #endif
24 namespace __sanitizer {
26 bool ReportFile::SupportsColors() {
27 SpinMutexLock l(mu);
28 ReopenIfNecessary();
29 return SupportsColoredOutput(fd);
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;
38 const char *flag = common_flags()->color;
39 return internal_strcmp(flag, "always") == 0 ||
40 (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
43 static void (*sandboxing_callback)();
44 void SetSandboxingCallback(void (*f)()) {
45 sandboxing_callback = f;
48 void 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;
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
65 static void (*SoftRssLimitExceededCallback)(bool exceeded);
66 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
67 CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
68 SoftRssLimitExceededCallback = Callback;
71 static AllocatorReleaseToOSCallback ReleseCallback;
72 void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback) {
73 CHECK_EQ(ReleseCallback, nullptr);
74 ReleseCallback = Callback;
77 #if SANITIZER_LINUX && !SANITIZER_GO
78 void 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;
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;
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();
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);
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;
137 #endif
139 void WriteToSyslog(const char *msg) {
140 InternalScopedString msg_copy(kErrorMessageBufferSize);
141 msg_copy.append("%s", msg);
142 char *p = msg_copy.data();
143 char *q;
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);
157 void 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
170 } // namespace __sanitizer
172 void NOINLINE
173 __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
174 __sanitizer::PrepareForSandboxing(args);
175 if (__sanitizer::sandboxing_callback)
176 __sanitizer::sandboxing_callback();