1*68d75effSDimitry Andric //===-- asan_report.cpp ---------------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric //
9*68d75effSDimitry Andric // This file is a part of AddressSanitizer, an address sanity checker.
10*68d75effSDimitry Andric //
11*68d75effSDimitry Andric // This file contains error reporting code.
12*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
13*68d75effSDimitry Andric 
14*68d75effSDimitry Andric #include "asan_errors.h"
15*68d75effSDimitry Andric #include "asan_flags.h"
16*68d75effSDimitry Andric #include "asan_descriptions.h"
17*68d75effSDimitry Andric #include "asan_internal.h"
18*68d75effSDimitry Andric #include "asan_mapping.h"
19*68d75effSDimitry Andric #include "asan_report.h"
20*68d75effSDimitry Andric #include "asan_scariness_score.h"
21*68d75effSDimitry Andric #include "asan_stack.h"
22*68d75effSDimitry Andric #include "asan_thread.h"
23*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
24*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
25*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h"
26*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
27*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
28*68d75effSDimitry Andric 
29*68d75effSDimitry Andric namespace __asan {
30*68d75effSDimitry Andric 
31*68d75effSDimitry Andric // -------------------- User-specified callbacks ----------------- {{{1
32*68d75effSDimitry Andric static void (*error_report_callback)(const char*);
33*68d75effSDimitry Andric static char *error_message_buffer = nullptr;
34*68d75effSDimitry Andric static uptr error_message_buffer_pos = 0;
35*68d75effSDimitry Andric static BlockingMutex error_message_buf_mutex(LINKER_INITIALIZED);
36*68d75effSDimitry Andric static const unsigned kAsanBuggyPcPoolSize = 25;
37*68d75effSDimitry Andric static __sanitizer::atomic_uintptr_t AsanBuggyPcPool[kAsanBuggyPcPoolSize];
38*68d75effSDimitry Andric 
39*68d75effSDimitry Andric void AppendToErrorMessageBuffer(const char *buffer) {
40*68d75effSDimitry Andric   BlockingMutexLock l(&error_message_buf_mutex);
41*68d75effSDimitry Andric   if (!error_message_buffer) {
42*68d75effSDimitry Andric     error_message_buffer =
43*68d75effSDimitry Andric       (char*)MmapOrDieQuietly(kErrorMessageBufferSize, __func__);
44*68d75effSDimitry Andric     error_message_buffer_pos = 0;
45*68d75effSDimitry Andric   }
46*68d75effSDimitry Andric   uptr length = internal_strlen(buffer);
47*68d75effSDimitry Andric   RAW_CHECK(kErrorMessageBufferSize >= error_message_buffer_pos);
48*68d75effSDimitry Andric   uptr remaining = kErrorMessageBufferSize - error_message_buffer_pos;
49*68d75effSDimitry Andric   internal_strncpy(error_message_buffer + error_message_buffer_pos,
50*68d75effSDimitry Andric                    buffer, remaining);
51*68d75effSDimitry Andric   error_message_buffer[kErrorMessageBufferSize - 1] = '\0';
52*68d75effSDimitry Andric   // FIXME: reallocate the buffer instead of truncating the message.
53*68d75effSDimitry Andric   error_message_buffer_pos += Min(remaining, length);
54*68d75effSDimitry Andric }
55*68d75effSDimitry Andric 
56*68d75effSDimitry Andric // ---------------------- Helper functions ----------------------- {{{1
57*68d75effSDimitry Andric 
58*68d75effSDimitry Andric void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
59*68d75effSDimitry Andric                      bool in_shadow, const char *after) {
60*68d75effSDimitry Andric   Decorator d;
61*68d75effSDimitry Andric   str->append("%s%s%x%x%s%s", before,
62*68d75effSDimitry Andric               in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
63*68d75effSDimitry Andric               byte & 15, d.Default(), after);
64*68d75effSDimitry Andric }
65*68d75effSDimitry Andric 
66*68d75effSDimitry Andric static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
67*68d75effSDimitry Andric                                 const char *zone_name) {
68*68d75effSDimitry Andric   if (zone_ptr) {
69*68d75effSDimitry Andric     if (zone_name) {
70*68d75effSDimitry Andric       Printf("malloc_zone_from_ptr(%p) = %p, which is %s\n",
71*68d75effSDimitry Andric                  ptr, zone_ptr, zone_name);
72*68d75effSDimitry Andric     } else {
73*68d75effSDimitry Andric       Printf("malloc_zone_from_ptr(%p) = %p, which doesn't have a name\n",
74*68d75effSDimitry Andric                  ptr, zone_ptr);
75*68d75effSDimitry Andric     }
76*68d75effSDimitry Andric   } else {
77*68d75effSDimitry Andric     Printf("malloc_zone_from_ptr(%p) = 0\n", ptr);
78*68d75effSDimitry Andric   }
79*68d75effSDimitry Andric }
80*68d75effSDimitry Andric 
81*68d75effSDimitry Andric // ---------------------- Address Descriptions ------------------- {{{1
82*68d75effSDimitry Andric 
83*68d75effSDimitry Andric bool ParseFrameDescription(const char *frame_descr,
84*68d75effSDimitry Andric                            InternalMmapVector<StackVarDescr> *vars) {
85*68d75effSDimitry Andric   CHECK(frame_descr);
86*68d75effSDimitry Andric   const char *p;
87*68d75effSDimitry Andric   // This string is created by the compiler and has the following form:
88*68d75effSDimitry Andric   // "n alloc_1 alloc_2 ... alloc_n"
89*68d75effSDimitry Andric   // where alloc_i looks like "offset size len ObjectName"
90*68d75effSDimitry Andric   // or                       "offset size len ObjectName:line".
91*68d75effSDimitry Andric   uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
92*68d75effSDimitry Andric   if (n_objects == 0)
93*68d75effSDimitry Andric     return false;
94*68d75effSDimitry Andric 
95*68d75effSDimitry Andric   for (uptr i = 0; i < n_objects; i++) {
96*68d75effSDimitry Andric     uptr beg  = (uptr)internal_simple_strtoll(p, &p, 10);
97*68d75effSDimitry Andric     uptr size = (uptr)internal_simple_strtoll(p, &p, 10);
98*68d75effSDimitry Andric     uptr len  = (uptr)internal_simple_strtoll(p, &p, 10);
99*68d75effSDimitry Andric     if (beg == 0 || size == 0 || *p != ' ') {
100*68d75effSDimitry Andric       return false;
101*68d75effSDimitry Andric     }
102*68d75effSDimitry Andric     p++;
103*68d75effSDimitry Andric     char *colon_pos = internal_strchr(p, ':');
104*68d75effSDimitry Andric     uptr line = 0;
105*68d75effSDimitry Andric     uptr name_len = len;
106*68d75effSDimitry Andric     if (colon_pos != nullptr && colon_pos < p + len) {
107*68d75effSDimitry Andric       name_len = colon_pos - p;
108*68d75effSDimitry Andric       line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
109*68d75effSDimitry Andric     }
110*68d75effSDimitry Andric     StackVarDescr var = {beg, size, p, name_len, line};
111*68d75effSDimitry Andric     vars->push_back(var);
112*68d75effSDimitry Andric     p += len;
113*68d75effSDimitry Andric   }
114*68d75effSDimitry Andric 
115*68d75effSDimitry Andric   return true;
116*68d75effSDimitry Andric }
117*68d75effSDimitry Andric 
118*68d75effSDimitry Andric // -------------------- Different kinds of reports ----------------- {{{1
119*68d75effSDimitry Andric 
120*68d75effSDimitry Andric // Use ScopedInErrorReport to run common actions just before and
121*68d75effSDimitry Andric // immediately after printing error report.
122*68d75effSDimitry Andric class ScopedInErrorReport {
123*68d75effSDimitry Andric  public:
124*68d75effSDimitry Andric   explicit ScopedInErrorReport(bool fatal = false)
125*68d75effSDimitry Andric       : halt_on_error_(fatal || flags()->halt_on_error) {
126*68d75effSDimitry Andric     // Make sure the registry and sanitizer report mutexes are locked while
127*68d75effSDimitry Andric     // we're printing an error report.
128*68d75effSDimitry Andric     // We can lock them only here to avoid self-deadlock in case of
129*68d75effSDimitry Andric     // recursive reports.
130*68d75effSDimitry Andric     asanThreadRegistry().Lock();
131*68d75effSDimitry Andric     Printf(
132*68d75effSDimitry Andric         "=================================================================\n");
133*68d75effSDimitry Andric   }
134*68d75effSDimitry Andric 
135*68d75effSDimitry Andric   ~ScopedInErrorReport() {
136*68d75effSDimitry Andric     if (halt_on_error_ && !__sanitizer_acquire_crash_state()) {
137*68d75effSDimitry Andric       asanThreadRegistry().Unlock();
138*68d75effSDimitry Andric       return;
139*68d75effSDimitry Andric     }
140*68d75effSDimitry Andric     ASAN_ON_ERROR();
141*68d75effSDimitry Andric     if (current_error_.IsValid()) current_error_.Print();
142*68d75effSDimitry Andric 
143*68d75effSDimitry Andric     // Make sure the current thread is announced.
144*68d75effSDimitry Andric     DescribeThread(GetCurrentThread());
145*68d75effSDimitry Andric     // We may want to grab this lock again when printing stats.
146*68d75effSDimitry Andric     asanThreadRegistry().Unlock();
147*68d75effSDimitry Andric     // Print memory stats.
148*68d75effSDimitry Andric     if (flags()->print_stats)
149*68d75effSDimitry Andric       __asan_print_accumulated_stats();
150*68d75effSDimitry Andric 
151*68d75effSDimitry Andric     if (common_flags()->print_cmdline)
152*68d75effSDimitry Andric       PrintCmdline();
153*68d75effSDimitry Andric 
154*68d75effSDimitry Andric     if (common_flags()->print_module_map == 2) PrintModuleMap();
155*68d75effSDimitry Andric 
156*68d75effSDimitry Andric     // Copy the message buffer so that we could start logging without holding a
157*68d75effSDimitry Andric     // lock that gets aquired during printing.
158*68d75effSDimitry Andric     InternalMmapVector<char> buffer_copy(kErrorMessageBufferSize);
159*68d75effSDimitry Andric     {
160*68d75effSDimitry Andric       BlockingMutexLock l(&error_message_buf_mutex);
161*68d75effSDimitry Andric       internal_memcpy(buffer_copy.data(),
162*68d75effSDimitry Andric                       error_message_buffer, kErrorMessageBufferSize);
163*68d75effSDimitry Andric     }
164*68d75effSDimitry Andric 
165*68d75effSDimitry Andric     LogFullErrorReport(buffer_copy.data());
166*68d75effSDimitry Andric 
167*68d75effSDimitry Andric     if (error_report_callback) {
168*68d75effSDimitry Andric       error_report_callback(buffer_copy.data());
169*68d75effSDimitry Andric     }
170*68d75effSDimitry Andric 
171*68d75effSDimitry Andric     if (halt_on_error_ && common_flags()->abort_on_error) {
172*68d75effSDimitry Andric       // On Android the message is truncated to 512 characters.
173*68d75effSDimitry Andric       // FIXME: implement "compact" error format, possibly without, or with
174*68d75effSDimitry Andric       // highly compressed stack traces?
175*68d75effSDimitry Andric       // FIXME: or just use the summary line as abort message?
176*68d75effSDimitry Andric       SetAbortMessage(buffer_copy.data());
177*68d75effSDimitry Andric     }
178*68d75effSDimitry Andric 
179*68d75effSDimitry Andric     // In halt_on_error = false mode, reset the current error object (before
180*68d75effSDimitry Andric     // unlocking).
181*68d75effSDimitry Andric     if (!halt_on_error_)
182*68d75effSDimitry Andric       internal_memset(&current_error_, 0, sizeof(current_error_));
183*68d75effSDimitry Andric 
184*68d75effSDimitry Andric     if (halt_on_error_) {
185*68d75effSDimitry Andric       Report("ABORTING\n");
186*68d75effSDimitry Andric       Die();
187*68d75effSDimitry Andric     }
188*68d75effSDimitry Andric   }
189*68d75effSDimitry Andric 
190*68d75effSDimitry Andric   void ReportError(const ErrorDescription &description) {
191*68d75effSDimitry Andric     // Can only report one error per ScopedInErrorReport.
192*68d75effSDimitry Andric     CHECK_EQ(current_error_.kind, kErrorKindInvalid);
193*68d75effSDimitry Andric     internal_memcpy(&current_error_, &description, sizeof(current_error_));
194*68d75effSDimitry Andric   }
195*68d75effSDimitry Andric 
196*68d75effSDimitry Andric   static ErrorDescription &CurrentError() {
197*68d75effSDimitry Andric     return current_error_;
198*68d75effSDimitry Andric   }
199*68d75effSDimitry Andric 
200*68d75effSDimitry Andric  private:
201*68d75effSDimitry Andric   ScopedErrorReportLock error_report_lock_;
202*68d75effSDimitry Andric   // Error currently being reported. This enables the destructor to interact
203*68d75effSDimitry Andric   // with the debugger and point it to an error description.
204*68d75effSDimitry Andric   static ErrorDescription current_error_;
205*68d75effSDimitry Andric   bool halt_on_error_;
206*68d75effSDimitry Andric };
207*68d75effSDimitry Andric 
208*68d75effSDimitry Andric ErrorDescription ScopedInErrorReport::current_error_(LINKER_INITIALIZED);
209*68d75effSDimitry Andric 
210*68d75effSDimitry Andric void ReportDeadlySignal(const SignalContext &sig) {
211*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
212*68d75effSDimitry Andric   ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
213*68d75effSDimitry Andric   in_report.ReportError(error);
214*68d75effSDimitry Andric }
215*68d75effSDimitry Andric 
216*68d75effSDimitry Andric void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack) {
217*68d75effSDimitry Andric   ScopedInErrorReport in_report;
218*68d75effSDimitry Andric   ErrorDoubleFree error(GetCurrentTidOrInvalid(), free_stack, addr);
219*68d75effSDimitry Andric   in_report.ReportError(error);
220*68d75effSDimitry Andric }
221*68d75effSDimitry Andric 
222*68d75effSDimitry Andric void ReportNewDeleteTypeMismatch(uptr addr, uptr delete_size,
223*68d75effSDimitry Andric                                  uptr delete_alignment,
224*68d75effSDimitry Andric                                  BufferedStackTrace *free_stack) {
225*68d75effSDimitry Andric   ScopedInErrorReport in_report;
226*68d75effSDimitry Andric   ErrorNewDeleteTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
227*68d75effSDimitry Andric                                    delete_size, delete_alignment);
228*68d75effSDimitry Andric   in_report.ReportError(error);
229*68d75effSDimitry Andric }
230*68d75effSDimitry Andric 
231*68d75effSDimitry Andric void ReportFreeNotMalloced(uptr addr, BufferedStackTrace *free_stack) {
232*68d75effSDimitry Andric   ScopedInErrorReport in_report;
233*68d75effSDimitry Andric   ErrorFreeNotMalloced error(GetCurrentTidOrInvalid(), free_stack, addr);
234*68d75effSDimitry Andric   in_report.ReportError(error);
235*68d75effSDimitry Andric }
236*68d75effSDimitry Andric 
237*68d75effSDimitry Andric void ReportAllocTypeMismatch(uptr addr, BufferedStackTrace *free_stack,
238*68d75effSDimitry Andric                              AllocType alloc_type,
239*68d75effSDimitry Andric                              AllocType dealloc_type) {
240*68d75effSDimitry Andric   ScopedInErrorReport in_report;
241*68d75effSDimitry Andric   ErrorAllocTypeMismatch error(GetCurrentTidOrInvalid(), free_stack, addr,
242*68d75effSDimitry Andric                                alloc_type, dealloc_type);
243*68d75effSDimitry Andric   in_report.ReportError(error);
244*68d75effSDimitry Andric }
245*68d75effSDimitry Andric 
246*68d75effSDimitry Andric void ReportMallocUsableSizeNotOwned(uptr addr, BufferedStackTrace *stack) {
247*68d75effSDimitry Andric   ScopedInErrorReport in_report;
248*68d75effSDimitry Andric   ErrorMallocUsableSizeNotOwned error(GetCurrentTidOrInvalid(), stack, addr);
249*68d75effSDimitry Andric   in_report.ReportError(error);
250*68d75effSDimitry Andric }
251*68d75effSDimitry Andric 
252*68d75effSDimitry Andric void ReportSanitizerGetAllocatedSizeNotOwned(uptr addr,
253*68d75effSDimitry Andric                                              BufferedStackTrace *stack) {
254*68d75effSDimitry Andric   ScopedInErrorReport in_report;
255*68d75effSDimitry Andric   ErrorSanitizerGetAllocatedSizeNotOwned error(GetCurrentTidOrInvalid(), stack,
256*68d75effSDimitry Andric                                                addr);
257*68d75effSDimitry Andric   in_report.ReportError(error);
258*68d75effSDimitry Andric }
259*68d75effSDimitry Andric 
260*68d75effSDimitry Andric void ReportCallocOverflow(uptr count, uptr size, BufferedStackTrace *stack) {
261*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
262*68d75effSDimitry Andric   ErrorCallocOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
263*68d75effSDimitry Andric   in_report.ReportError(error);
264*68d75effSDimitry Andric }
265*68d75effSDimitry Andric 
266*68d75effSDimitry Andric void ReportReallocArrayOverflow(uptr count, uptr size,
267*68d75effSDimitry Andric                                 BufferedStackTrace *stack) {
268*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
269*68d75effSDimitry Andric   ErrorReallocArrayOverflow error(GetCurrentTidOrInvalid(), stack, count, size);
270*68d75effSDimitry Andric   in_report.ReportError(error);
271*68d75effSDimitry Andric }
272*68d75effSDimitry Andric 
273*68d75effSDimitry Andric void ReportPvallocOverflow(uptr size, BufferedStackTrace *stack) {
274*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
275*68d75effSDimitry Andric   ErrorPvallocOverflow error(GetCurrentTidOrInvalid(), stack, size);
276*68d75effSDimitry Andric   in_report.ReportError(error);
277*68d75effSDimitry Andric }
278*68d75effSDimitry Andric 
279*68d75effSDimitry Andric void ReportInvalidAllocationAlignment(uptr alignment,
280*68d75effSDimitry Andric                                       BufferedStackTrace *stack) {
281*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
282*68d75effSDimitry Andric   ErrorInvalidAllocationAlignment error(GetCurrentTidOrInvalid(), stack,
283*68d75effSDimitry Andric                                         alignment);
284*68d75effSDimitry Andric   in_report.ReportError(error);
285*68d75effSDimitry Andric }
286*68d75effSDimitry Andric 
287*68d75effSDimitry Andric void ReportInvalidAlignedAllocAlignment(uptr size, uptr alignment,
288*68d75effSDimitry Andric                                         BufferedStackTrace *stack) {
289*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
290*68d75effSDimitry Andric   ErrorInvalidAlignedAllocAlignment error(GetCurrentTidOrInvalid(), stack,
291*68d75effSDimitry Andric                                           size, alignment);
292*68d75effSDimitry Andric   in_report.ReportError(error);
293*68d75effSDimitry Andric }
294*68d75effSDimitry Andric 
295*68d75effSDimitry Andric void ReportInvalidPosixMemalignAlignment(uptr alignment,
296*68d75effSDimitry Andric                                          BufferedStackTrace *stack) {
297*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
298*68d75effSDimitry Andric   ErrorInvalidPosixMemalignAlignment error(GetCurrentTidOrInvalid(), stack,
299*68d75effSDimitry Andric                                            alignment);
300*68d75effSDimitry Andric   in_report.ReportError(error);
301*68d75effSDimitry Andric }
302*68d75effSDimitry Andric 
303*68d75effSDimitry Andric void ReportAllocationSizeTooBig(uptr user_size, uptr total_size, uptr max_size,
304*68d75effSDimitry Andric                                 BufferedStackTrace *stack) {
305*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
306*68d75effSDimitry Andric   ErrorAllocationSizeTooBig error(GetCurrentTidOrInvalid(), stack, user_size,
307*68d75effSDimitry Andric                                   total_size, max_size);
308*68d75effSDimitry Andric   in_report.ReportError(error);
309*68d75effSDimitry Andric }
310*68d75effSDimitry Andric 
311*68d75effSDimitry Andric void ReportRssLimitExceeded(BufferedStackTrace *stack) {
312*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
313*68d75effSDimitry Andric   ErrorRssLimitExceeded error(GetCurrentTidOrInvalid(), stack);
314*68d75effSDimitry Andric   in_report.ReportError(error);
315*68d75effSDimitry Andric }
316*68d75effSDimitry Andric 
317*68d75effSDimitry Andric void ReportOutOfMemory(uptr requested_size, BufferedStackTrace *stack) {
318*68d75effSDimitry Andric   ScopedInErrorReport in_report(/*fatal*/ true);
319*68d75effSDimitry Andric   ErrorOutOfMemory error(GetCurrentTidOrInvalid(), stack, requested_size);
320*68d75effSDimitry Andric   in_report.ReportError(error);
321*68d75effSDimitry Andric }
322*68d75effSDimitry Andric 
323*68d75effSDimitry Andric void ReportStringFunctionMemoryRangesOverlap(const char *function,
324*68d75effSDimitry Andric                                              const char *offset1, uptr length1,
325*68d75effSDimitry Andric                                              const char *offset2, uptr length2,
326*68d75effSDimitry Andric                                              BufferedStackTrace *stack) {
327*68d75effSDimitry Andric   ScopedInErrorReport in_report;
328*68d75effSDimitry Andric   ErrorStringFunctionMemoryRangesOverlap error(
329*68d75effSDimitry Andric       GetCurrentTidOrInvalid(), stack, (uptr)offset1, length1, (uptr)offset2,
330*68d75effSDimitry Andric       length2, function);
331*68d75effSDimitry Andric   in_report.ReportError(error);
332*68d75effSDimitry Andric }
333*68d75effSDimitry Andric 
334*68d75effSDimitry Andric void ReportStringFunctionSizeOverflow(uptr offset, uptr size,
335*68d75effSDimitry Andric                                       BufferedStackTrace *stack) {
336*68d75effSDimitry Andric   ScopedInErrorReport in_report;
337*68d75effSDimitry Andric   ErrorStringFunctionSizeOverflow error(GetCurrentTidOrInvalid(), stack, offset,
338*68d75effSDimitry Andric                                         size);
339*68d75effSDimitry Andric   in_report.ReportError(error);
340*68d75effSDimitry Andric }
341*68d75effSDimitry Andric 
342*68d75effSDimitry Andric void ReportBadParamsToAnnotateContiguousContainer(uptr beg, uptr end,
343*68d75effSDimitry Andric                                                   uptr old_mid, uptr new_mid,
344*68d75effSDimitry Andric                                                   BufferedStackTrace *stack) {
345*68d75effSDimitry Andric   ScopedInErrorReport in_report;
346*68d75effSDimitry Andric   ErrorBadParamsToAnnotateContiguousContainer error(
347*68d75effSDimitry Andric       GetCurrentTidOrInvalid(), stack, beg, end, old_mid, new_mid);
348*68d75effSDimitry Andric   in_report.ReportError(error);
349*68d75effSDimitry Andric }
350*68d75effSDimitry Andric 
351*68d75effSDimitry Andric void ReportODRViolation(const __asan_global *g1, u32 stack_id1,
352*68d75effSDimitry Andric                         const __asan_global *g2, u32 stack_id2) {
353*68d75effSDimitry Andric   ScopedInErrorReport in_report;
354*68d75effSDimitry Andric   ErrorODRViolation error(GetCurrentTidOrInvalid(), g1, stack_id1, g2,
355*68d75effSDimitry Andric                           stack_id2);
356*68d75effSDimitry Andric   in_report.ReportError(error);
357*68d75effSDimitry Andric }
358*68d75effSDimitry Andric 
359*68d75effSDimitry Andric // ----------------------- CheckForInvalidPointerPair ----------- {{{1
360*68d75effSDimitry Andric static NOINLINE void ReportInvalidPointerPair(uptr pc, uptr bp, uptr sp,
361*68d75effSDimitry Andric                                               uptr a1, uptr a2) {
362*68d75effSDimitry Andric   ScopedInErrorReport in_report;
363*68d75effSDimitry Andric   ErrorInvalidPointerPair error(GetCurrentTidOrInvalid(), pc, bp, sp, a1, a2);
364*68d75effSDimitry Andric   in_report.ReportError(error);
365*68d75effSDimitry Andric }
366*68d75effSDimitry Andric 
367*68d75effSDimitry Andric static bool IsInvalidPointerPair(uptr a1, uptr a2) {
368*68d75effSDimitry Andric   if (a1 == a2)
369*68d75effSDimitry Andric     return false;
370*68d75effSDimitry Andric 
371*68d75effSDimitry Andric   // 256B in shadow memory can be iterated quite fast
372*68d75effSDimitry Andric   static const uptr kMaxOffset = 2048;
373*68d75effSDimitry Andric 
374*68d75effSDimitry Andric   uptr left = a1 < a2 ? a1 : a2;
375*68d75effSDimitry Andric   uptr right = a1 < a2 ? a2 : a1;
376*68d75effSDimitry Andric   uptr offset = right - left;
377*68d75effSDimitry Andric   if (offset <= kMaxOffset)
378*68d75effSDimitry Andric     return __asan_region_is_poisoned(left, offset);
379*68d75effSDimitry Andric 
380*68d75effSDimitry Andric   AsanThread *t = GetCurrentThread();
381*68d75effSDimitry Andric 
382*68d75effSDimitry Andric   // check whether left is a stack memory pointer
383*68d75effSDimitry Andric   if (uptr shadow_offset1 = t->GetStackVariableShadowStart(left)) {
384*68d75effSDimitry Andric     uptr shadow_offset2 = t->GetStackVariableShadowStart(right);
385*68d75effSDimitry Andric     return shadow_offset2 == 0 || shadow_offset1 != shadow_offset2;
386*68d75effSDimitry Andric   }
387*68d75effSDimitry Andric 
388*68d75effSDimitry Andric   // check whether left is a heap memory address
389*68d75effSDimitry Andric   HeapAddressDescription hdesc1, hdesc2;
390*68d75effSDimitry Andric   if (GetHeapAddressInformation(left, 0, &hdesc1) &&
391*68d75effSDimitry Andric       hdesc1.chunk_access.access_type == kAccessTypeInside)
392*68d75effSDimitry Andric     return !GetHeapAddressInformation(right, 0, &hdesc2) ||
393*68d75effSDimitry Andric         hdesc2.chunk_access.access_type != kAccessTypeInside ||
394*68d75effSDimitry Andric         hdesc1.chunk_access.chunk_begin != hdesc2.chunk_access.chunk_begin;
395*68d75effSDimitry Andric 
396*68d75effSDimitry Andric   // check whether left is an address of a global variable
397*68d75effSDimitry Andric   GlobalAddressDescription gdesc1, gdesc2;
398*68d75effSDimitry Andric   if (GetGlobalAddressInformation(left, 0, &gdesc1))
399*68d75effSDimitry Andric     return !GetGlobalAddressInformation(right - 1, 0, &gdesc2) ||
400*68d75effSDimitry Andric         !gdesc1.PointsInsideTheSameVariable(gdesc2);
401*68d75effSDimitry Andric 
402*68d75effSDimitry Andric   if (t->GetStackVariableShadowStart(right) ||
403*68d75effSDimitry Andric       GetHeapAddressInformation(right, 0, &hdesc2) ||
404*68d75effSDimitry Andric       GetGlobalAddressInformation(right - 1, 0, &gdesc2))
405*68d75effSDimitry Andric     return true;
406*68d75effSDimitry Andric 
407*68d75effSDimitry Andric   // At this point we know nothing about both a1 and a2 addresses.
408*68d75effSDimitry Andric   return false;
409*68d75effSDimitry Andric }
410*68d75effSDimitry Andric 
411*68d75effSDimitry Andric static INLINE void CheckForInvalidPointerPair(void *p1, void *p2) {
412*68d75effSDimitry Andric   switch (flags()->detect_invalid_pointer_pairs) {
413*68d75effSDimitry Andric     case 0:
414*68d75effSDimitry Andric       return;
415*68d75effSDimitry Andric     case 1:
416*68d75effSDimitry Andric       if (p1 == nullptr || p2 == nullptr)
417*68d75effSDimitry Andric         return;
418*68d75effSDimitry Andric       break;
419*68d75effSDimitry Andric   }
420*68d75effSDimitry Andric 
421*68d75effSDimitry Andric   uptr a1 = reinterpret_cast<uptr>(p1);
422*68d75effSDimitry Andric   uptr a2 = reinterpret_cast<uptr>(p2);
423*68d75effSDimitry Andric 
424*68d75effSDimitry Andric   if (IsInvalidPointerPair(a1, a2)) {
425*68d75effSDimitry Andric     GET_CALLER_PC_BP_SP;
426*68d75effSDimitry Andric     ReportInvalidPointerPair(pc, bp, sp, a1, a2);
427*68d75effSDimitry Andric   }
428*68d75effSDimitry Andric }
429*68d75effSDimitry Andric // ----------------------- Mac-specific reports ----------------- {{{1
430*68d75effSDimitry Andric 
431*68d75effSDimitry Andric void ReportMacMzReallocUnknown(uptr addr, uptr zone_ptr, const char *zone_name,
432*68d75effSDimitry Andric                                BufferedStackTrace *stack) {
433*68d75effSDimitry Andric   ScopedInErrorReport in_report;
434*68d75effSDimitry Andric   Printf("mz_realloc(%p) -- attempting to realloc unallocated memory.\n"
435*68d75effSDimitry Andric              "This is an unrecoverable problem, exiting now.\n",
436*68d75effSDimitry Andric              addr);
437*68d75effSDimitry Andric   PrintZoneForPointer(addr, zone_ptr, zone_name);
438*68d75effSDimitry Andric   stack->Print();
439*68d75effSDimitry Andric   DescribeAddressIfHeap(addr);
440*68d75effSDimitry Andric }
441*68d75effSDimitry Andric 
442*68d75effSDimitry Andric // -------------- SuppressErrorReport -------------- {{{1
443*68d75effSDimitry Andric // Avoid error reports duplicating for ASan recover mode.
444*68d75effSDimitry Andric static bool SuppressErrorReport(uptr pc) {
445*68d75effSDimitry Andric   if (!common_flags()->suppress_equal_pcs) return false;
446*68d75effSDimitry Andric   for (unsigned i = 0; i < kAsanBuggyPcPoolSize; i++) {
447*68d75effSDimitry Andric     uptr cmp = atomic_load_relaxed(&AsanBuggyPcPool[i]);
448*68d75effSDimitry Andric     if (cmp == 0 && atomic_compare_exchange_strong(&AsanBuggyPcPool[i], &cmp,
449*68d75effSDimitry Andric                                                    pc, memory_order_relaxed))
450*68d75effSDimitry Andric       return false;
451*68d75effSDimitry Andric     if (cmp == pc) return true;
452*68d75effSDimitry Andric   }
453*68d75effSDimitry Andric   Die();
454*68d75effSDimitry Andric }
455*68d75effSDimitry Andric 
456*68d75effSDimitry Andric void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
457*68d75effSDimitry Andric                         uptr access_size, u32 exp, bool fatal) {
458*68d75effSDimitry Andric   if (!fatal && SuppressErrorReport(pc)) return;
459*68d75effSDimitry Andric   ENABLE_FRAME_POINTER;
460*68d75effSDimitry Andric 
461*68d75effSDimitry Andric   // Optimization experiments.
462*68d75effSDimitry Andric   // The experiments can be used to evaluate potential optimizations that remove
463*68d75effSDimitry Andric   // instrumentation (assess false negatives). Instead of completely removing
464*68d75effSDimitry Andric   // some instrumentation, compiler can emit special calls into runtime
465*68d75effSDimitry Andric   // (e.g. __asan_report_exp_load1 instead of __asan_report_load1) and pass
466*68d75effSDimitry Andric   // mask of experiments (exp).
467*68d75effSDimitry Andric   // The reaction to a non-zero value of exp is to be defined.
468*68d75effSDimitry Andric   (void)exp;
469*68d75effSDimitry Andric 
470*68d75effSDimitry Andric   ScopedInErrorReport in_report(fatal);
471*68d75effSDimitry Andric   ErrorGeneric error(GetCurrentTidOrInvalid(), pc, bp, sp, addr, is_write,
472*68d75effSDimitry Andric                      access_size);
473*68d75effSDimitry Andric   in_report.ReportError(error);
474*68d75effSDimitry Andric }
475*68d75effSDimitry Andric 
476*68d75effSDimitry Andric }  // namespace __asan
477*68d75effSDimitry Andric 
478*68d75effSDimitry Andric // --------------------------- Interface --------------------- {{{1
479*68d75effSDimitry Andric using namespace __asan;
480*68d75effSDimitry Andric 
481*68d75effSDimitry Andric void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
482*68d75effSDimitry Andric                          uptr access_size, u32 exp) {
483*68d75effSDimitry Andric   ENABLE_FRAME_POINTER;
484*68d75effSDimitry Andric   bool fatal = flags()->halt_on_error;
485*68d75effSDimitry Andric   ReportGenericError(pc, bp, sp, addr, is_write, access_size, exp, fatal);
486*68d75effSDimitry Andric }
487*68d75effSDimitry Andric 
488*68d75effSDimitry Andric void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
489*68d75effSDimitry Andric   BlockingMutexLock l(&error_message_buf_mutex);
490*68d75effSDimitry Andric   error_report_callback = callback;
491*68d75effSDimitry Andric }
492*68d75effSDimitry Andric 
493*68d75effSDimitry Andric void __asan_describe_address(uptr addr) {
494*68d75effSDimitry Andric   // Thread registry must be locked while we're describing an address.
495*68d75effSDimitry Andric   asanThreadRegistry().Lock();
496*68d75effSDimitry Andric   PrintAddressDescription(addr, 1, "");
497*68d75effSDimitry Andric   asanThreadRegistry().Unlock();
498*68d75effSDimitry Andric }
499*68d75effSDimitry Andric 
500*68d75effSDimitry Andric int __asan_report_present() {
501*68d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
502*68d75effSDimitry Andric }
503*68d75effSDimitry Andric 
504*68d75effSDimitry Andric uptr __asan_get_report_pc() {
505*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
506*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.pc;
507*68d75effSDimitry Andric   return 0;
508*68d75effSDimitry Andric }
509*68d75effSDimitry Andric 
510*68d75effSDimitry Andric uptr __asan_get_report_bp() {
511*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
512*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bp;
513*68d75effSDimitry Andric   return 0;
514*68d75effSDimitry Andric }
515*68d75effSDimitry Andric 
516*68d75effSDimitry Andric uptr __asan_get_report_sp() {
517*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
518*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.sp;
519*68d75effSDimitry Andric   return 0;
520*68d75effSDimitry Andric }
521*68d75effSDimitry Andric 
522*68d75effSDimitry Andric uptr __asan_get_report_address() {
523*68d75effSDimitry Andric   ErrorDescription &err = ScopedInErrorReport::CurrentError();
524*68d75effSDimitry Andric   if (err.kind == kErrorKindGeneric)
525*68d75effSDimitry Andric     return err.Generic.addr_description.Address();
526*68d75effSDimitry Andric   else if (err.kind == kErrorKindDoubleFree)
527*68d75effSDimitry Andric     return err.DoubleFree.addr_description.addr;
528*68d75effSDimitry Andric   return 0;
529*68d75effSDimitry Andric }
530*68d75effSDimitry Andric 
531*68d75effSDimitry Andric int __asan_get_report_access_type() {
532*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
533*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.is_write;
534*68d75effSDimitry Andric   return 0;
535*68d75effSDimitry Andric }
536*68d75effSDimitry Andric 
537*68d75effSDimitry Andric uptr __asan_get_report_access_size() {
538*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
539*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.access_size;
540*68d75effSDimitry Andric   return 0;
541*68d75effSDimitry Andric }
542*68d75effSDimitry Andric 
543*68d75effSDimitry Andric const char *__asan_get_report_description() {
544*68d75effSDimitry Andric   if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
545*68d75effSDimitry Andric     return ScopedInErrorReport::CurrentError().Generic.bug_descr;
546*68d75effSDimitry Andric   return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
547*68d75effSDimitry Andric }
548*68d75effSDimitry Andric 
549*68d75effSDimitry Andric extern "C" {
550*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
551*68d75effSDimitry Andric void __sanitizer_ptr_sub(void *a, void *b) {
552*68d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
553*68d75effSDimitry Andric }
554*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
555*68d75effSDimitry Andric void __sanitizer_ptr_cmp(void *a, void *b) {
556*68d75effSDimitry Andric   CheckForInvalidPointerPair(a, b);
557*68d75effSDimitry Andric }
558*68d75effSDimitry Andric } // extern "C"
559*68d75effSDimitry Andric 
560*68d75effSDimitry Andric // Provide default implementation of __asan_on_error that does nothing
561*68d75effSDimitry Andric // and may be overriden by user.
562*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
563