File: | compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp |
Warning: | line 183, column 34 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- segv_handler_posix.cpp ----------------------------------*- C++ -*-===// | |||
2 | // | |||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
4 | // See https://llvm.org/LICENSE.txt for license information. | |||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
6 | // | |||
7 | //===----------------------------------------------------------------------===// | |||
8 | ||||
9 | #include "gwp_asan/common.h" | |||
10 | #include "gwp_asan/crash_handler.h" | |||
11 | #include "gwp_asan/guarded_pool_allocator.h" | |||
12 | #include "gwp_asan/optional/segv_handler.h" | |||
13 | #include "gwp_asan/options.h" | |||
14 | ||||
15 | // RHEL creates the PRIu64 format macro (for printing uint64_t's) only when this | |||
16 | // macro is defined before including <inttypes.h>. | |||
17 | #ifndef __STDC_FORMAT_MACROS1 | |||
18 | #define __STDC_FORMAT_MACROS1 1 | |||
19 | #endif | |||
20 | ||||
21 | #include <assert.h> | |||
22 | #include <inttypes.h> | |||
23 | #include <signal.h> | |||
24 | #include <stdio.h> | |||
25 | ||||
26 | using gwp_asan::AllocationMetadata; | |||
27 | using gwp_asan::Error; | |||
28 | using gwp_asan::GuardedPoolAllocator; | |||
29 | using gwp_asan::Printf_t; | |||
30 | using gwp_asan::backtrace::PrintBacktrace_t; | |||
31 | using gwp_asan::backtrace::SegvBacktrace_t; | |||
32 | ||||
33 | namespace { | |||
34 | ||||
35 | struct ScopedEndOfReportDecorator { | |||
36 | ScopedEndOfReportDecorator(gwp_asan::Printf_t Printf) : Printf(Printf) {} | |||
37 | ~ScopedEndOfReportDecorator() { Printf("*** End GWP-ASan report ***\n"); } | |||
38 | gwp_asan::Printf_t Printf; | |||
39 | }; | |||
40 | ||||
41 | // Prints the provided error and metadata information. | |||
42 | void printHeader(Error E, uintptr_t AccessPtr, | |||
43 | const gwp_asan::AllocationMetadata *Metadata, | |||
44 | Printf_t Printf) { | |||
45 | // Print using intermediate strings. Platforms like Android don't like when | |||
46 | // you print multiple times to the same line, as there may be a newline | |||
47 | // appended to a log file automatically per Printf() call. | |||
48 | constexpr size_t kDescriptionBufferLen = 128; | |||
49 | char DescriptionBuffer[kDescriptionBufferLen] = ""; | |||
50 | if (E != Error::UNKNOWN && Metadata != nullptr) { | |||
51 | uintptr_t Address = __gwp_asan_get_allocation_address(Metadata); | |||
52 | size_t Size = __gwp_asan_get_allocation_size(Metadata); | |||
53 | if (E == Error::USE_AFTER_FREE) { | |||
54 | snprintf(DescriptionBuffer, kDescriptionBufferLen, | |||
55 | "(%zu byte%s into a %zu-byte allocation at 0x%zx) ", | |||
56 | AccessPtr - Address, (AccessPtr - Address == 1) ? "" : "s", Size, | |||
57 | Address); | |||
58 | } else if (AccessPtr < Address) { | |||
59 | snprintf(DescriptionBuffer, kDescriptionBufferLen, | |||
60 | "(%zu byte%s to the left of a %zu-byte allocation at 0x%zx) ", | |||
61 | Address - AccessPtr, (Address - AccessPtr == 1) ? "" : "s", Size, | |||
62 | Address); | |||
63 | } else if (AccessPtr > Address) { | |||
64 | snprintf(DescriptionBuffer, kDescriptionBufferLen, | |||
65 | "(%zu byte%s to the right of a %zu-byte allocation at 0x%zx) ", | |||
66 | AccessPtr - Address, (AccessPtr - Address == 1) ? "" : "s", Size, | |||
67 | Address); | |||
68 | } else { | |||
69 | snprintf(DescriptionBuffer, kDescriptionBufferLen, | |||
70 | "(a %zu-byte allocation) ", Size); | |||
71 | } | |||
72 | } | |||
73 | ||||
74 | // Possible number of digits of a 64-bit number: ceil(log10(2^64)) == 20. Add | |||
75 | // a null terminator, and round to the nearest 8-byte boundary. | |||
76 | uint64_t ThreadID = gwp_asan::getThreadID(); | |||
77 | constexpr size_t kThreadBufferLen = 24; | |||
78 | char ThreadBuffer[kThreadBufferLen]; | |||
79 | if (ThreadID == gwp_asan::kInvalidThreadID) | |||
80 | snprintf(ThreadBuffer, kThreadBufferLen, "<unknown>"); | |||
81 | else | |||
82 | snprintf(ThreadBuffer, kThreadBufferLen, "%" PRIu64"l" "u", ThreadID); | |||
83 | ||||
84 | Printf("%s at 0x%zx %sby thread %s here:\n", gwp_asan::ErrorToString(E), | |||
85 | AccessPtr, DescriptionBuffer, ThreadBuffer); | |||
86 | } | |||
87 | ||||
88 | void dumpReport(uintptr_t ErrorPtr, const gwp_asan::AllocatorState *State, | |||
89 | const gwp_asan::AllocationMetadata *Metadata, | |||
90 | SegvBacktrace_t SegvBacktrace, Printf_t Printf, | |||
91 | PrintBacktrace_t PrintBacktrace, void *Context) { | |||
92 | assert(State && "dumpReport missing Allocator State.")(static_cast <bool> (State && "dumpReport missing Allocator State." ) ? void (0) : __assert_fail ("State && \"dumpReport missing Allocator State.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 92, __extension__ __PRETTY_FUNCTION__)); | |||
93 | assert(Metadata && "dumpReport missing Metadata.")(static_cast <bool> (Metadata && "dumpReport missing Metadata." ) ? void (0) : __assert_fail ("Metadata && \"dumpReport missing Metadata.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 93, __extension__ __PRETTY_FUNCTION__)); | |||
94 | assert(Printf && "dumpReport missing Printf.")(static_cast <bool> (Printf && "dumpReport missing Printf." ) ? void (0) : __assert_fail ("Printf && \"dumpReport missing Printf.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 94, __extension__ __PRETTY_FUNCTION__)); | |||
95 | ||||
96 | if (!__gwp_asan_error_is_mine(State, ErrorPtr)) | |||
97 | return; | |||
98 | ||||
99 | Printf("*** GWP-ASan detected a memory error ***\n"); | |||
100 | ScopedEndOfReportDecorator Decorator(Printf); | |||
101 | ||||
102 | uintptr_t InternalErrorPtr = __gwp_asan_get_internal_crash_address(State); | |||
103 | if (InternalErrorPtr != 0u) | |||
104 | ErrorPtr = InternalErrorPtr; | |||
105 | ||||
106 | Error E = __gwp_asan_diagnose_error(State, Metadata, ErrorPtr); | |||
107 | ||||
108 | if (E == Error::UNKNOWN) { | |||
109 | Printf("GWP-ASan cannot provide any more information about this error. " | |||
110 | "This may occur due to a wild memory access into the GWP-ASan pool, " | |||
111 | "or an overflow/underflow that is > 512B in length.\n"); | |||
112 | return; | |||
113 | } | |||
114 | ||||
115 | const gwp_asan::AllocationMetadata *AllocMeta = | |||
116 | __gwp_asan_get_metadata(State, Metadata, ErrorPtr); | |||
117 | ||||
118 | // Print the error header. | |||
119 | printHeader(E, ErrorPtr, AllocMeta, Printf); | |||
120 | ||||
121 | // Print the fault backtrace. | |||
122 | static constexpr unsigned kMaximumStackFramesForCrashTrace = 512; | |||
123 | uintptr_t Trace[kMaximumStackFramesForCrashTrace]; | |||
124 | size_t TraceLength = | |||
125 | SegvBacktrace(Trace, kMaximumStackFramesForCrashTrace, Context); | |||
126 | ||||
127 | PrintBacktrace(Trace, TraceLength, Printf); | |||
128 | ||||
129 | if (AllocMeta == nullptr) | |||
130 | return; | |||
131 | ||||
132 | // Maybe print the deallocation trace. | |||
133 | if (__gwp_asan_is_deallocated(AllocMeta)) { | |||
134 | uint64_t ThreadID = __gwp_asan_get_deallocation_thread_id(AllocMeta); | |||
135 | if (ThreadID == gwp_asan::kInvalidThreadID) | |||
136 | Printf("0x%zx was deallocated by thread <unknown> here:\n", ErrorPtr); | |||
137 | else | |||
138 | Printf("0x%zx was deallocated by thread %zu here:\n", ErrorPtr, ThreadID); | |||
139 | TraceLength = __gwp_asan_get_deallocation_trace( | |||
140 | AllocMeta, Trace, kMaximumStackFramesForCrashTrace); | |||
141 | PrintBacktrace(Trace, TraceLength, Printf); | |||
142 | } | |||
143 | ||||
144 | // Print the allocation trace. | |||
145 | uint64_t ThreadID = __gwp_asan_get_allocation_thread_id(AllocMeta); | |||
146 | if (ThreadID == gwp_asan::kInvalidThreadID) | |||
147 | Printf("0x%zx was allocated by thread <unknown> here:\n", ErrorPtr); | |||
148 | else | |||
149 | Printf("0x%zx was allocated by thread %zu here:\n", ErrorPtr, ThreadID); | |||
150 | TraceLength = __gwp_asan_get_allocation_trace( | |||
151 | AllocMeta, Trace, kMaximumStackFramesForCrashTrace); | |||
152 | PrintBacktrace(Trace, TraceLength, Printf); | |||
153 | } | |||
154 | ||||
155 | struct sigaction PreviousHandler; | |||
156 | bool SignalHandlerInstalled; | |||
157 | gwp_asan::GuardedPoolAllocator *GPAForSignalHandler; | |||
158 | Printf_t PrintfForSignalHandler; | |||
159 | PrintBacktrace_t PrintBacktraceForSignalHandler; | |||
160 | SegvBacktrace_t BacktraceForSignalHandler; | |||
161 | ||||
162 | static void sigSegvHandler(int sig, siginfo_t *info, void *ucontext) { | |||
163 | if (GPAForSignalHandler) { | |||
| ||||
164 | GPAForSignalHandler->stop(); | |||
165 | ||||
166 | dumpReport(reinterpret_cast<uintptr_t>(info->si_addr_sifields._sigfault.si_addr), | |||
167 | GPAForSignalHandler->getAllocatorState(), | |||
168 | GPAForSignalHandler->getMetadataRegion(), | |||
169 | BacktraceForSignalHandler, PrintfForSignalHandler, | |||
170 | PrintBacktraceForSignalHandler, ucontext); | |||
171 | } | |||
172 | ||||
173 | // Process any previous handlers. | |||
174 | if (PreviousHandler.sa_flags & SA_SIGINFO4) { | |||
175 | PreviousHandler.sa_sigaction__sigaction_handler.sa_sigaction(sig, info, ucontext); | |||
176 | } else if (PreviousHandler.sa_handler__sigaction_handler.sa_handler == SIG_DFL((__sighandler_t) 0)) { | |||
177 | // If the previous handler was the default handler, cause a core dump. | |||
178 | signal(SIGSEGV11, SIG_DFL((__sighandler_t) 0)); | |||
179 | raise(SIGSEGV11); | |||
180 | } else if (PreviousHandler.sa_handler__sigaction_handler.sa_handler == SIG_IGN((__sighandler_t) 1)) { | |||
181 | // If the previous segv handler was SIGIGN, crash iff we were responsible | |||
182 | // for the crash. | |||
183 | if (__gwp_asan_error_is_mine(GPAForSignalHandler->getAllocatorState(), | |||
| ||||
184 | reinterpret_cast<uintptr_t>(info->si_addr_sifields._sigfault.si_addr))) { | |||
185 | signal(SIGSEGV11, SIG_DFL((__sighandler_t) 0)); | |||
186 | raise(SIGSEGV11); | |||
187 | } | |||
188 | } else { | |||
189 | PreviousHandler.sa_handler__sigaction_handler.sa_handler(sig); | |||
190 | } | |||
191 | } | |||
192 | } // anonymous namespace | |||
193 | ||||
194 | namespace gwp_asan { | |||
195 | namespace segv_handler { | |||
196 | ||||
197 | void installSignalHandlers(gwp_asan::GuardedPoolAllocator *GPA, Printf_t Printf, | |||
198 | PrintBacktrace_t PrintBacktrace, | |||
199 | SegvBacktrace_t SegvBacktrace) { | |||
200 | assert(GPA && "GPA wasn't provided to installSignalHandlers.")(static_cast <bool> (GPA && "GPA wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("GPA && \"GPA wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 200, __extension__ __PRETTY_FUNCTION__)); | |||
201 | assert(Printf && "Printf wasn't provided to installSignalHandlers.")(static_cast <bool> (Printf && "Printf wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("Printf && \"Printf wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 201, __extension__ __PRETTY_FUNCTION__)); | |||
202 | assert(PrintBacktrace &&(static_cast <bool> (PrintBacktrace && "PrintBacktrace wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("PrintBacktrace && \"PrintBacktrace wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 203, __extension__ __PRETTY_FUNCTION__)) | |||
203 | "PrintBacktrace wasn't provided to installSignalHandlers.")(static_cast <bool> (PrintBacktrace && "PrintBacktrace wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("PrintBacktrace && \"PrintBacktrace wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 203, __extension__ __PRETTY_FUNCTION__)); | |||
204 | assert(SegvBacktrace &&(static_cast <bool> (SegvBacktrace && "SegvBacktrace wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("SegvBacktrace && \"SegvBacktrace wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 205, __extension__ __PRETTY_FUNCTION__)) | |||
205 | "SegvBacktrace wasn't provided to installSignalHandlers.")(static_cast <bool> (SegvBacktrace && "SegvBacktrace wasn't provided to installSignalHandlers." ) ? void (0) : __assert_fail ("SegvBacktrace && \"SegvBacktrace wasn't provided to installSignalHandlers.\"" , "/build/llvm-toolchain-snapshot-14~++20211110111138+cffbfd01e37b/compiler-rt/lib/gwp_asan/optional/segv_handler_posix.cpp" , 205, __extension__ __PRETTY_FUNCTION__)); | |||
206 | GPAForSignalHandler = GPA; | |||
207 | PrintfForSignalHandler = Printf; | |||
208 | PrintBacktraceForSignalHandler = PrintBacktrace; | |||
209 | BacktraceForSignalHandler = SegvBacktrace; | |||
210 | ||||
211 | struct sigaction Action = {}; | |||
212 | Action.sa_sigaction__sigaction_handler.sa_sigaction = sigSegvHandler; | |||
213 | Action.sa_flags = SA_SIGINFO4; | |||
214 | sigaction(SIGSEGV11, &Action, &PreviousHandler); | |||
215 | SignalHandlerInstalled = true; | |||
216 | } | |||
217 | ||||
218 | void uninstallSignalHandlers() { | |||
219 | if (SignalHandlerInstalled) { | |||
220 | sigaction(SIGSEGV11, &PreviousHandler, nullptr); | |||
221 | SignalHandlerInstalled = false; | |||
222 | } | |||
223 | } | |||
224 | } // namespace segv_handler | |||
225 | } // namespace gwp_asan |