Implement P0315R4, Lambdas in unevaluated contexts.
[official-gcc.git] / libsanitizer / sanitizer_common / sanitizer_symbolizer_report.cc
blob1157724125e3b8ef6213dd83a14244460b5f2884
1 //===-- sanitizer_symbolizer_report.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 other sanitizer run-time
9 /// libraries and implements symbolized reports related functions.
10 ///
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common.h"
14 #include "sanitizer_file.h"
15 #include "sanitizer_flags.h"
16 #include "sanitizer_procmaps.h"
17 #include "sanitizer_report_decorator.h"
18 #include "sanitizer_stacktrace.h"
19 #include "sanitizer_stacktrace_printer.h"
20 #include "sanitizer_symbolizer.h"
22 #if SANITIZER_POSIX
23 # include "sanitizer_posix.h"
24 # include <sys/mman.h>
25 #endif
27 namespace __sanitizer {
29 #if !SANITIZER_GO
30 void ReportErrorSummary(const char *error_type, const AddressInfo &info,
31 const char *alt_tool_name) {
32 if (!common_flags()->print_summary) return;
33 InternalScopedString buff(kMaxSummaryLength);
34 buff.append("%s ", error_type);
35 RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
36 common_flags()->strip_path_prefix);
37 ReportErrorSummary(buff.data(), alt_tool_name);
39 #endif
41 #if !SANITIZER_FUCHSIA
43 bool ReportFile::SupportsColors() {
44 SpinMutexLock l(mu);
45 ReopenIfNecessary();
46 return SupportsColoredOutput(fd);
49 static INLINE bool ReportSupportsColors() {
50 return report_file.SupportsColors();
53 #else // SANITIZER_FUCHSIA
55 // Fuchsia's logs always go through post-processing that handles colorization.
56 static INLINE bool ReportSupportsColors() { return true; }
58 #endif // !SANITIZER_FUCHSIA
60 bool ColorizeReports() {
61 // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
62 // printing on Windows.
63 if (SANITIZER_WINDOWS)
64 return false;
66 const char *flag = common_flags()->color;
67 return internal_strcmp(flag, "always") == 0 ||
68 (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
71 void ReportErrorSummary(const char *error_type, const StackTrace *stack,
72 const char *alt_tool_name) {
73 #if !SANITIZER_GO
74 if (!common_flags()->print_summary)
75 return;
76 if (stack->size == 0) {
77 ReportErrorSummary(error_type);
78 return;
80 // Currently, we include the first stack frame into the report summary.
81 // Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
82 uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
83 SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
84 ReportErrorSummary(error_type, frame->info, alt_tool_name);
85 frame->ClearAll();
86 #endif
89 void ReportMmapWriteExec(int prot) {
90 #if SANITIZER_POSIX && (!SANITIZER_GO && !SANITIZER_ANDROID)
91 if ((prot & (PROT_WRITE | PROT_EXEC)) != (PROT_WRITE | PROT_EXEC))
92 return;
94 ScopedErrorReportLock l;
95 SanitizerCommonDecorator d;
97 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
98 BufferedStackTrace *stack = stack_buffer.data();
99 stack->Reset();
100 uptr top = 0;
101 uptr bottom = 0;
102 GET_CALLER_PC_BP_SP;
103 (void)sp;
104 bool fast = common_flags()->fast_unwind_on_fatal;
105 if (fast)
106 GetThreadStackTopAndBottom(false, &top, &bottom);
107 stack->Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom, fast);
109 Printf("%s", d.Warning());
110 Report("WARNING: %s: writable-executable page usage\n", SanitizerToolName);
111 Printf("%s", d.Default());
113 stack->Print();
114 ReportErrorSummary("w-and-x-usage", stack);
115 #endif
118 #if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_GO
119 void StartReportDeadlySignal() {
120 // Write the first message using fd=2, just in case.
121 // It may actually fail to write in case stderr is closed.
122 CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
123 static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
124 CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
127 static void MaybeReportNonExecRegion(uptr pc) {
128 #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
129 MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
130 MemoryMappedSegment segment;
131 while (proc_maps.Next(&segment)) {
132 if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
133 Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
135 #endif
138 static void PrintMemoryByte(InternalScopedString *str, const char *before,
139 u8 byte) {
140 SanitizerCommonDecorator d;
141 str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
142 d.Default());
145 static void MaybeDumpInstructionBytes(uptr pc) {
146 if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
147 return;
148 InternalScopedString str(1024);
149 str.append("First 16 instruction bytes at pc: ");
150 if (IsAccessibleMemoryRange(pc, 16)) {
151 for (int i = 0; i < 16; ++i) {
152 PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
154 str.append("\n");
155 } else {
156 str.append("unaccessible\n");
158 Report("%s", str.data());
161 static void MaybeDumpRegisters(void *context) {
162 if (!common_flags()->dump_registers) return;
163 SignalContext::DumpAllRegisters(context);
166 static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
167 UnwindSignalStackCallbackType unwind,
168 const void *unwind_context) {
169 SanitizerCommonDecorator d;
170 Printf("%s", d.Warning());
171 static const char kDescription[] = "stack-overflow";
172 Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
173 SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
174 (void *)sig.bp, (void *)sig.sp, tid);
175 Printf("%s", d.Default());
176 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
177 BufferedStackTrace *stack = stack_buffer.data();
178 stack->Reset();
179 unwind(sig, unwind_context, stack);
180 stack->Print();
181 ReportErrorSummary(kDescription, stack);
184 static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
185 UnwindSignalStackCallbackType unwind,
186 const void *unwind_context) {
187 SanitizerCommonDecorator d;
188 Printf("%s", d.Warning());
189 const char *description = sig.Describe();
190 Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
191 SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
192 (void *)sig.bp, (void *)sig.sp, tid);
193 Printf("%s", d.Default());
194 if (sig.pc < GetPageSizeCached())
195 Report("Hint: pc points to the zero page.\n");
196 if (sig.is_memory_access) {
197 const char *access_type =
198 sig.write_flag == SignalContext::WRITE
199 ? "WRITE"
200 : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
201 Report("The signal is caused by a %s memory access.\n", access_type);
202 if (sig.addr < GetPageSizeCached())
203 Report("Hint: address points to the zero page.\n");
205 MaybeReportNonExecRegion(sig.pc);
206 InternalMmapVector<BufferedStackTrace> stack_buffer(1);
207 BufferedStackTrace *stack = stack_buffer.data();
208 stack->Reset();
209 unwind(sig, unwind_context, stack);
210 stack->Print();
211 MaybeDumpInstructionBytes(sig.pc);
212 MaybeDumpRegisters(sig.context);
213 Printf("%s can not provide additional info.\n", SanitizerToolName);
214 ReportErrorSummary(description, stack);
217 void ReportDeadlySignal(const SignalContext &sig, u32 tid,
218 UnwindSignalStackCallbackType unwind,
219 const void *unwind_context) {
220 if (sig.IsStackOverflow())
221 ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
222 else
223 ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
226 void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
227 UnwindSignalStackCallbackType unwind,
228 const void *unwind_context) {
229 StartReportDeadlySignal();
230 ScopedErrorReportLock rl;
231 SignalContext sig(siginfo, context);
232 ReportDeadlySignal(sig, tid, unwind, unwind_context);
233 Report("ABORTING\n");
234 Die();
237 #endif // !SANITIZER_FUCHSIA && !SANITIZER_GO
239 static atomic_uintptr_t reporting_thread = {0};
240 static StaticSpinMutex CommonSanitizerReportMutex;
242 ScopedErrorReportLock::ScopedErrorReportLock() {
243 uptr current = GetThreadSelf();
244 for (;;) {
245 uptr expected = 0;
246 if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
247 memory_order_relaxed)) {
248 // We've claimed reporting_thread so proceed.
249 CommonSanitizerReportMutex.Lock();
250 return;
253 if (expected == current) {
254 // This is either asynch signal or nested error during error reporting.
255 // Fail simple to avoid deadlocks in Report().
257 // Can't use Report() here because of potential deadlocks in nested
258 // signal handlers.
259 CatastrophicErrorWrite(SanitizerToolName,
260 internal_strlen(SanitizerToolName));
261 static const char msg[] = ": nested bug in the same thread, aborting.\n";
262 CatastrophicErrorWrite(msg, sizeof(msg) - 1);
264 internal__exit(common_flags()->exitcode);
267 internal_sched_yield();
271 ScopedErrorReportLock::~ScopedErrorReportLock() {
272 CommonSanitizerReportMutex.Unlock();
273 atomic_store_relaxed(&reporting_thread, 0);
276 void ScopedErrorReportLock::CheckLocked() {
277 CommonSanitizerReportMutex.CheckLocked();
280 } // namespace __sanitizer