K-HHC
C++ Header-only Library for Hexahexacontadecimal Encoding/Decoding
Loading...
Searching...
No Matches
hhc_assert.hpp
Go to the documentation of this file.
1#ifndef HHC_ASSERT_HPP
2#define HHC_ASSERT_HPP
3
4#if defined(__clang__)
5# define HHC_NO_PROFILE __attribute__((no_profile_instrument_function))
6#else
7# define HHC_NO_PROFILE
8#endif
9
10// The stack-trace / diagnostic machinery (iostream, execinfo, windows.h,
11// dbghelp) is only compiled into debug builds. Release builds reduce
12// HHC_ASSERT to a bare trap, so consumers do not pay for heavyweight
13// includes, static iostream initialization, or platform header pollution.
14#ifndef NDEBUG
15
16#include <cstdlib>
17#include <iostream>
18
19// Platform-specific includes for stack traces
20// Check Windows first (clang-cl defines __clang__ but not __unix__)
21#if defined(_WIN32) || defined(_WIN64)
22 #ifndef NOMINMAX
23 #define NOMINMAX // Prevent Windows from defining min/max macros
24 #endif
25 #include <windows.h>
26 #include <dbghelp.h>
27 #define HHC_HAVE_STACKWALK 1
28 #define HHC_HAVE_BACKTRACE 0 // Windows doesn't use backtrace
29 #pragma comment(lib, "dbghelp.lib")
30#elif defined(__unix__) || defined(__APPLE__) || defined(__linux__) || defined(__MACH__)
31 // Feature detection for execinfo.h (not available on musl without libexecinfo)
32 #if defined(__has_include)
33 #if __has_include(<execinfo.h>)
34 #include <execinfo.h>
35 #define HHC_HAVE_BACKTRACE 1
36 #else
37 // execinfo.h not available (e.g., musl without libexecinfo-dev)
38 #define HHC_HAVE_BACKTRACE 0
39 #endif
40 #else
41 // Fallback for compilers without __has_include (pre-C++17)
42 // Assume execinfo.h is available on glibc systems
43 #if defined(__GLIBC__)
44 #include <execinfo.h>
45 #define HHC_HAVE_BACKTRACE 1
46 #else
47 // On non-glibc systems (e.g., musl), execinfo.h may not be available
48 // unless libexecinfo is installed and linked
49 #define HHC_HAVE_BACKTRACE 0
50 #endif
51 #endif
52 #include <unistd.h>
53 #define HHC_HAVE_STACKWALK 0 // Unix systems don't use Windows stack walk
54#else
55 // Unknown platform
56 #define HHC_HAVE_BACKTRACE 0
57 #define HHC_HAVE_STACKWALK 0
58#endif
59
60#endif // !NDEBUG
61
62namespace hhc::detail {
63
64#ifdef LLVM_BUILD_INSTRUMENTED
65extern "C" int __llvm_profile_write_file(void);
67 (void)__llvm_profile_write_file();
68}
69#else
70inline void flush_coverage_profile() {}
71#endif
72
73#ifndef NDEBUG
78
79#if HHC_HAVE_BACKTRACE
80 // Unix-like systems (Linux, macOS, BSD) with execinfo.h available
81 constexpr int max_frames = 64;
82 void* buffer[max_frames];
83
84 int frame_count = backtrace(buffer, max_frames);
85
86 std::cerr << "\n=== Stack Trace ===\n";
87 backtrace_symbols_fd(buffer, frame_count, STDERR_FILENO);
88 std::cerr << "===================\n\n";
89
90#elif HHC_HAVE_STACKWALK
91 // Windows stack walk
92 constexpr int max_frames = 64;
93 void* stack[max_frames];
94
95 HANDLE process = GetCurrentProcess();
96 SymInitialize(process, NULL, TRUE);
97
98 WORD frame_count = CaptureStackBackTrace(0, max_frames, stack, NULL);
99
100 std::cerr << "\n=== Stack Trace ===\n";
101
102 SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
103 if (symbol) {
104 symbol->MaxNameLen = 255;
105 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
106
107 for (int i = 0; i < frame_count; i++) {
108 if (SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol)) {
109 std::cerr << " " << symbol->Name << " [0x" << std::hex << symbol->Address << std::dec << "]\n";
110 } else {
111 std::cerr << " [0x" << std::hex << (DWORD64)stack[i] << std::dec << "]\n";
112 }
113 }
114
115 free(symbol);
116 }
117
118 std::cerr << "===================\n\n";
119 SymCleanup(process);
120
121#else
122 // Fallback: no stack trace available (e.g., musl without libexecinfo)
123 std::cerr << "\n[Stack trace not available on this platform]\n\n";
124#endif
125 }
126#endif // !NDEBUG
127
139 [[noreturn]] HHC_NO_PROFILE inline void assertion_failed(const char* expression,
140 const char* file,
141 const int line,
142 const char* function) {
143#ifndef NDEBUG
144 // Debug build: provide stack trace and error message
145 std::cerr << "\n╔═════════════════════════════════════════════════════════════╗\n"
146 << "║ HHC ASSERTION FAILED ║\n"
147 << "╚═════════════════════════════════════════════════════════════╝\n\n"
148 << "Expression: " << expression << '\n'
149 << "Location: " << file << ':' << line << '\n'
150 << "Function: " << function << '\n';
151
153
154 std::cerr << "This is a critical error indicating a bug in the HHC library.\n"
155 << "Please report this issue with the above information.\n\n";
156
158 std::abort();
159#else
160 // Release build: generate trap instruction
161 // This tells the compiler this code path is unreachable,
162 // enabling aggressive optimizations while still catching bugs
163
164 // Suppress unused parameter warnings
165 (void)expression;
166 (void)file;
167 (void)line;
168 (void)function;
169
171
172 // Use compiler built-in to generate trap instruction
173 #if defined(__GNUC__) || defined(__clang__)
174 __builtin_trap();
175 #elif defined(_MSC_VER)
176 __debugbreak();
177 #else
178 #error "Unsupported compiler (no trap instruction)"
179 #endif
180
181 // Tell compiler this is unreachable
182 #if defined(__GNUC__) || defined(__clang__)
183 __builtin_unreachable();
184 #elif defined(_MSC_VER)
185 __assume(0);
186 #else
187 #error "Unsupported compiler (no unreachable instruction)"
188 #endif
189#endif
190 }
191
192} // namespace hhc::detail
193
210#define HHC_ASSERT(expr) \
211 do { \
212 if (!(expr)) { \
213 ::hhc::detail::assertion_failed( \
214 #expr, \
215 __FILE__, \
216 __LINE__, \
217 __func__ \
218 ); \
219 } \
220 } while (0)
221
233#define HHC_ASSERT_MSG(expr, msg) \
234 do { \
235 if (!(expr)) { \
236 ::hhc::detail::assertion_failed( \
237 #expr " (" msg ")", \
238 __FILE__, \
239 __LINE__, \
240 __func__ \
241 ); \
242 } \
243 } while (0)
244
261#define HHC_UNREACHABLE(msg) \
262 ::hhc::detail::assertion_failed( \
263 "Unreachable code: " msg, \
264 __FILE__, \
265 __LINE__, \
266 __func__ \
267 )
268
269#endif // HHC_ASSERT_HPP
#define HHC_NO_PROFILE
Definition hhc_assert.hpp:7
Definition hhc_assert.hpp:62
HHC_NO_PROFILE void print_stack_trace()
Print stack trace (debug builds only)
Definition hhc_assert.hpp:77
void flush_coverage_profile()
Definition hhc_assert.hpp:70
HHC_NO_PROFILE void assertion_failed(const char *expression, const char *file, const int line, const char *function)
Handle assertion failure.
Definition hhc_assert.hpp:139