2018-02-19 Sebastian Perta <sebastian.perta@renesas.com>
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_common_libcdep.cc
bloba3f35319e23fa52d011fc5d0d8c7763d108f874c
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_file.h"
16 #include "sanitizer_flags.h"
17 #include "sanitizer_procmaps.h"
18 #include "sanitizer_report_decorator.h"
19 #include "sanitizer_stackdepot.h"
20 #include "sanitizer_stacktrace.h"
21 #include "sanitizer_symbolizer.h"
23 #if SANITIZER_POSIX
24 #include "sanitizer_posix.h"
25 #endif
27 namespace __sanitizer {
29 #if !SANITIZER_FUCHSIA
31 bool ReportFile::SupportsColors() {
32 SpinMutexLock l(mu);
33 ReopenIfNecessary();
34 return SupportsColoredOutput(fd);
37 static INLINE bool ReportSupportsColors() {
38 return report_file.SupportsColors();
41 #else // SANITIZER_FUCHSIA
43 // Fuchsia's logs always go through post-processing that handles colorization.
44 static INLINE bool ReportSupportsColors() { return true; }
46 #endif // !SANITIZER_FUCHSIA
48 bool ColorizeReports() {
49 // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
50 // printing on Windows.
51 if (SANITIZER_WINDOWS)
52 return false;
54 const char *flag = common_flags()->color;
55 return internal_strcmp(flag, "always") == 0 ||
56 (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
59 static void (*sandboxing_callback)();
60 void SetSandboxingCallback(void (*f)()) {
61 sandboxing_callback = f;
64 void ReportErrorSummary(const char *error_type, const StackTrace *stack,
65 const char *alt_tool_name) {
66 #if !SANITIZER_GO
67 if (!common_flags()->print_summary)
68 return;
69 if (stack->size == 0) {
70 ReportErrorSummary(error_type);
71 return;
73 // Currently, we include the first stack frame into the report summary.
74 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
75 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
76 SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
77 ReportErrorSummary(error_type, frame->info, alt_tool_name);
78 frame->ClearAll();
79 #endif
82 static void (*SoftRssLimitExceededCallback)(bool exceeded);
83 void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
84 CHECK_EQ(SoftRssLimitExceededCallback, nullptr);
85 SoftRssLimitExceededCallback = Callback;
88 #if SANITIZER_LINUX && !SANITIZER_GO
89 void BackgroundThread(void *arg) {
90 uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
91 uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
92 bool heap_profile = common_flags()->heap_profile;
93 uptr prev_reported_rss = 0;
94 uptr prev_reported_stack_depot_size = 0;
95 bool reached_soft_rss_limit = false;
96 uptr rss_during_last_reported_profile = 0;
97 while (true) {
98 SleepForMillis(100);
99 uptr current_rss_mb = GetRSS() >> 20;
100 if (Verbosity()) {
101 // If RSS has grown 10% since last time, print some information.
102 if (prev_reported_rss * 11 / 10 < current_rss_mb) {
103 Printf("%s: RSS: %zdMb\n", SanitizerToolName, current_rss_mb);
104 prev_reported_rss = current_rss_mb;
106 // If stack depot has grown 10% since last time, print it too.
107 StackDepotStats *stack_depot_stats = StackDepotGetStats();
108 if (prev_reported_stack_depot_size * 11 / 10 <
109 stack_depot_stats->allocated) {
110 Printf("%s: StackDepot: %zd ids; %zdM allocated\n",
111 SanitizerToolName,
112 stack_depot_stats->n_uniq_ids,
113 stack_depot_stats->allocated >> 20);
114 prev_reported_stack_depot_size = stack_depot_stats->allocated;
117 // Check RSS against the limit.
118 if (hard_rss_limit_mb && hard_rss_limit_mb < current_rss_mb) {
119 Report("%s: hard rss limit exhausted (%zdMb vs %zdMb)\n",
120 SanitizerToolName, hard_rss_limit_mb, current_rss_mb);
121 DumpProcessMap();
122 Die();
124 if (soft_rss_limit_mb) {
125 if (soft_rss_limit_mb < current_rss_mb && !reached_soft_rss_limit) {
126 reached_soft_rss_limit = true;
127 Report("%s: soft rss limit exhausted (%zdMb vs %zdMb)\n",
128 SanitizerToolName, soft_rss_limit_mb, current_rss_mb);
129 if (SoftRssLimitExceededCallback)
130 SoftRssLimitExceededCallback(true);
131 } else if (soft_rss_limit_mb >= current_rss_mb &&
132 reached_soft_rss_limit) {
133 reached_soft_rss_limit = false;
134 if (SoftRssLimitExceededCallback)
135 SoftRssLimitExceededCallback(false);
138 if (heap_profile &&
139 current_rss_mb > rss_during_last_reported_profile * 1.1) {
140 Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
141 __sanitizer_print_memory_profile(90, 20);
142 rss_during_last_reported_profile = current_rss_mb;
146 #endif
148 #if !SANITIZER_FUCHSIA && !SANITIZER_GO
149 void StartReportDeadlySignal() {
150 // Write the first message using fd=2, just in case.
151 // It may actually fail to write in case stderr is closed.
152 CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
153 static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
154 CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
157 static void MaybeReportNonExecRegion(uptr pc) {
158 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
159 MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
160 MemoryMappedSegment segment;
161 while (proc_maps.Next(&segment)) {
162 if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
163 Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
165 #endif
168 static void PrintMemoryByte(InternalScopedString *str, const char *before,
169 u8 byte) {
170 SanitizerCommonDecorator d;
171 str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
172 d.Default());
175 static void MaybeDumpInstructionBytes(uptr pc) {
176 if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
177 return;
178 InternalScopedString str(1024);
179 str.append("First 16 instruction bytes at pc: ");
180 if (IsAccessibleMemoryRange(pc, 16)) {
181 for (int i = 0; i < 16; ++i) {
182 PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
184 str.append("\n");
185 } else {
186 str.append("unaccessible\n");
188 Report("%s", str.data());
191 static void MaybeDumpRegisters(void *context) {
192 if (!common_flags()->dump_registers) return;
193 SignalContext::DumpAllRegisters(context);
196 static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
197 UnwindSignalStackCallbackType unwind,
198 const void *unwind_context) {
199 SanitizerCommonDecorator d;
200 Printf("%s", d.Warning());
201 static const char kDescription[] = "stack-overflow";
202 Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
203 SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
204 (void *)sig.bp, (void *)sig.sp, tid);
205 Printf("%s", d.Default());
206 InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
207 BufferedStackTrace *stack = stack_buffer.data();
208 stack->Reset();
209 unwind(sig, unwind_context, stack);
210 stack->Print();
211 ReportErrorSummary(kDescription, stack);
214 static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
215 UnwindSignalStackCallbackType unwind,
216 const void *unwind_context) {
217 SanitizerCommonDecorator d;
218 Printf("%s", d.Warning());
219 const char *description = sig.Describe();
220 Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
221 SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
222 (void *)sig.bp, (void *)sig.sp, tid);
223 Printf("%s", d.Default());
224 if (sig.pc < GetPageSizeCached())
225 Report("Hint: pc points to the zero page.\n");
226 if (sig.is_memory_access) {
227 const char *access_type =
228 sig.write_flag == SignalContext::WRITE
229 ? "WRITE"
230 : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
231 Report("The signal is caused by a %s memory access.\n", access_type);
232 if (sig.addr < GetPageSizeCached())
233 Report("Hint: address points to the zero page.\n");
235 MaybeReportNonExecRegion(sig.pc);
236 InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
237 BufferedStackTrace *stack = stack_buffer.data();
238 stack->Reset();
239 unwind(sig, unwind_context, stack);
240 stack->Print();
241 MaybeDumpInstructionBytes(sig.pc);
242 MaybeDumpRegisters(sig.context);
243 Printf("%s can not provide additional info.\n", SanitizerToolName);
244 ReportErrorSummary(description, stack);
247 void ReportDeadlySignal(const SignalContext &sig, u32 tid,
248 UnwindSignalStackCallbackType unwind,
249 const void *unwind_context) {
250 if (sig.IsStackOverflow())
251 ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
252 else
253 ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
256 void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
257 UnwindSignalStackCallbackType unwind,
258 const void *unwind_context) {
259 StartReportDeadlySignal();
260 ScopedErrorReportLock rl;
261 SignalContext sig(siginfo, context);
262 ReportDeadlySignal(sig, tid, unwind, unwind_context);
263 Report("ABORTING\n");
264 Die();
267 #endif // !SANITIZER_FUCHSIA && !SANITIZER_GO
269 void WriteToSyslog(const char *msg) {
270 InternalScopedString msg_copy(kErrorMessageBufferSize);
271 msg_copy.append("%s", msg);
272 char *p = msg_copy.data();
273 char *q;
275 // Print one line at a time.
276 // syslog, at least on Android, has an implicit message length limit.
277 do {
278 q = internal_strchr(p, '\n');
279 if (q)
280 *q = '\0';
281 WriteOneLineToSyslog(p);
282 if (q)
283 p = q + 1;
284 } while (q);
287 void MaybeStartBackgroudThread() {
288 #if SANITIZER_LINUX && \
289 !SANITIZER_GO // Need to implement/test on other platforms.
290 // Start the background thread if one of the rss limits is given.
291 if (!common_flags()->hard_rss_limit_mb &&
292 !common_flags()->soft_rss_limit_mb &&
293 !common_flags()->heap_profile) return;
294 if (!&real_pthread_create) return; // Can't spawn the thread anyway.
295 internal_start_thread(BackgroundThread, nullptr);
296 #endif
299 static atomic_uintptr_t reporting_thread = {0};
301 ScopedErrorReportLock::ScopedErrorReportLock() {
302 uptr current = GetThreadSelf();
303 for (;;) {
304 uptr expected = 0;
305 if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
306 memory_order_relaxed)) {
307 // We've claimed reporting_thread so proceed.
308 CommonSanitizerReportMutex.Lock();
309 return;
312 if (expected == current) {
313 // This is either asynch signal or nested error during error reporting.
314 // Fail simple to avoid deadlocks in Report().
316 // Can't use Report() here because of potential deadlocks in nested
317 // signal handlers.
318 CatastrophicErrorWrite(SanitizerToolName,
319 internal_strlen(SanitizerToolName));
320 static const char msg[] = ": nested bug in the same thread, aborting.\n";
321 CatastrophicErrorWrite(msg, sizeof(msg) - 1);
323 internal__exit(common_flags()->exitcode);
326 internal_sched_yield();
330 ScopedErrorReportLock::~ScopedErrorReportLock() {
331 CommonSanitizerReportMutex.Unlock();
332 atomic_store_relaxed(&reporting_thread, 0);
335 void ScopedErrorReportLock::CheckLocked() {
336 CommonSanitizerReportMutex.CheckLocked();
339 } // namespace __sanitizer
341 SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
342 __sanitizer_sandbox_arguments *args) {
343 __sanitizer::PrepareForSandboxing(args);
344 if (__sanitizer::sandboxing_callback)
345 __sanitizer::sandboxing_callback();