abort.cc (3140B)
1 // Copyright 2019 Google LLC 2 // Copyright 2024 Arm Limited and/or its affiliates <open-source-office@arm.com> 3 // SPDX-License-Identifier: Apache-2.0 4 // SPDX-License-Identifier: BSD-3-Clause 5 6 #include "hwy/abort.h" 7 8 #include <stdarg.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 12 #include <atomic> 13 #include <string> 14 15 #include "hwy/base.h" 16 17 #if HWY_IS_ASAN || HWY_IS_MSAN || HWY_IS_TSAN 18 #include "sanitizer/common_interface_defs.h" // __sanitizer_print_stack_trace 19 #endif 20 21 namespace hwy { 22 23 namespace { 24 25 std::atomic<WarnFunc>& AtomicWarnFunc() { 26 static std::atomic<WarnFunc> func; 27 return func; 28 } 29 30 std::atomic<AbortFunc>& AtomicAbortFunc() { 31 static std::atomic<AbortFunc> func; 32 return func; 33 } 34 35 std::string GetBaseName(std::string const& file_name) { 36 auto last_slash = file_name.find_last_of("/\\"); 37 return file_name.substr(last_slash + 1); 38 } 39 40 } // namespace 41 42 // Returning a reference is unfortunately incompatible with `std::atomic`, which 43 // is required to safely implement `SetWarnFunc`. As a workaround, we store a 44 // copy here, update it when called, and return a reference to the copy. This 45 // has the added benefit of protecting the actual pointer from modification. 46 HWY_DLLEXPORT WarnFunc& GetWarnFunc() { 47 static WarnFunc func; 48 func = AtomicWarnFunc().load(); 49 return func; 50 } 51 52 HWY_DLLEXPORT AbortFunc& GetAbortFunc() { 53 static AbortFunc func; 54 func = AtomicAbortFunc().load(); 55 return func; 56 } 57 58 HWY_DLLEXPORT WarnFunc SetWarnFunc(WarnFunc func) { 59 return AtomicWarnFunc().exchange(func); 60 } 61 62 HWY_DLLEXPORT AbortFunc SetAbortFunc(AbortFunc func) { 63 return AtomicAbortFunc().exchange(func); 64 } 65 66 HWY_DLLEXPORT void HWY_FORMAT(3, 4) 67 Warn(const char* file, int line, const char* format, ...) { 68 char buf[800]; 69 va_list args; 70 va_start(args, format); 71 vsnprintf(buf, sizeof(buf), format, args); 72 va_end(args); 73 74 WarnFunc handler = AtomicWarnFunc().load(); 75 if (handler != nullptr) { 76 handler(file, line, buf); 77 } else { 78 fprintf(stderr, "Warn at %s:%d: %s\n", GetBaseName(file).data(), line, buf); 79 } 80 } 81 82 HWY_DLLEXPORT HWY_NORETURN void HWY_FORMAT(3, 4) 83 Abort(const char* file, int line, const char* format, ...) { 84 char buf[800]; 85 va_list args; 86 va_start(args, format); 87 vsnprintf(buf, sizeof(buf), format, args); 88 va_end(args); 89 90 AbortFunc handler = AtomicAbortFunc().load(); 91 if (handler != nullptr) { 92 handler(file, line, buf); 93 } else { 94 fprintf(stderr, "Abort at %s:%d: %s\n", GetBaseName(file).data(), line, 95 buf); 96 } 97 98 // If compiled with any sanitizer, they can also print a stack trace. 99 #if HWY_IS_ASAN || HWY_IS_MSAN || HWY_IS_TSAN 100 __sanitizer_print_stack_trace(); 101 #endif // HWY_IS_* 102 fflush(stderr); 103 104 // Now terminate the program: 105 #if HWY_ARCH_RISCV 106 exit(1); // trap/abort just freeze Spike. 107 #elif HWY_IS_DEBUG_BUILD && !HWY_COMPILER_MSVC && !HWY_ARCH_ARM 108 // Facilitates breaking into a debugger, but don't use this in non-debug 109 // builds because it looks like "illegal instruction", which is misleading. 110 // Also does not work on Arm. 111 __builtin_trap(); 112 #else 113 abort(); // Compile error without this due to HWY_NORETURN. 114 #endif 115 } 116 117 } // namespace hwy