1 //===-- sanitizer_common_libcdep.cc ---------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
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"
24 #include "sanitizer_posix.h"
27 namespace __sanitizer
{
29 #if !SANITIZER_FUCHSIA
31 bool ReportFile::SupportsColors() {
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
)
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
) {
67 if (!common_flags()->print_summary
)
69 if (stack
->size
== 0) {
70 ReportErrorSummary(error_type
);
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
);
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;
99 uptr current_rss_mb
= GetRSS() >> 20;
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",
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
);
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);
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
;
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");
168 static void PrintMemoryByte(InternalScopedString
*str
, const char *before
,
170 SanitizerCommonDecorator d
;
171 str
->append("%s%s%x%x%s ", before
, d
.MemoryByte(), byte
>> 4, byte
& 15,
175 static void MaybeDumpInstructionBytes(uptr pc
) {
176 if (!common_flags()->dump_instruction_bytes
|| (pc
< GetPageSizeCached()))
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
]);
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();
209 unwind(sig
, unwind_context
, stack
);
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
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();
239 unwind(sig
, unwind_context
, stack
);
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
);
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");
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();
275 // Print one line at a time.
276 // syslog, at least on Android, has an implicit message length limit.
278 q
= internal_strchr(p
, '\n');
281 WriteOneLineToSyslog(p
);
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);
299 static atomic_uintptr_t reporting_thread
= {0};
301 ScopedErrorReportLock::ScopedErrorReportLock() {
302 uptr current
= GetThreadSelf();
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();
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
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();