| 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"ll" "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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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~++20210828111110+16086d47c0d0/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 |