1 | // |
2 | // Bugcheck.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: Bugcheck |
7 | // |
8 | // Definition of the Bugcheck class and the self-testing macros. |
9 | // |
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | |
16 | |
17 | #ifndef Foundation_Bugcheck_INCLUDED |
18 | #define Foundation_Bugcheck_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Foundation.h" |
22 | #include <string> |
23 | #include <cstdlib> |
24 | #if defined(_DEBUG) |
25 | # include <iostream> |
26 | #endif |
27 | |
28 | |
29 | namespace Poco { |
30 | |
31 | |
32 | class Foundation_API Bugcheck |
33 | /// This class provides some static methods that are |
34 | /// used by the |
35 | /// poco_assert_dbg(), poco_assert(), poco_check_ptr(), |
36 | /// poco_bugcheck() and poco_unexpected() macros. |
37 | /// You should not invoke these methods |
38 | /// directly. Use the macros instead, as they |
39 | /// automatically provide useful context information. |
40 | { |
41 | public: |
42 | static void assertion(const char* cond, const char* file, int line, const char* text = 0); |
43 | /// An assertion failed. Break into the debugger, if |
44 | /// possible, then throw an AssertionViolationException. |
45 | |
46 | static void nullPointer(const char* ptr, const char* file, int line); |
47 | /// An null pointer was encountered. Break into the debugger, if |
48 | /// possible, then throw an NullPointerException. |
49 | |
50 | static void bugcheck(const char* file, int line); |
51 | /// An internal error was encountered. Break into the debugger, if |
52 | /// possible, then throw an BugcheckException. |
53 | |
54 | static void bugcheck(const char* msg, const char* file, int line); |
55 | /// An internal error was encountered. Break into the debugger, if |
56 | /// possible, then throw an BugcheckException. |
57 | |
58 | static void unexpected(const char* file, int line); |
59 | /// An exception was caught in a destructor. Break into debugger, |
60 | /// if possible and report exception. Must only be called from |
61 | /// within a catch () block as it rethrows the exception to |
62 | /// determine its class. |
63 | |
64 | static void debugger(const char* file, int line); |
65 | /// An internal error was encountered. Break into the debugger, if |
66 | /// possible. |
67 | |
68 | static void debugger(const char* msg, const char* file, int line); |
69 | /// An internal error was encountered. Break into the debugger, if |
70 | /// possible. |
71 | |
72 | protected: |
73 | static std::string what(const char* msg, const char* file, int line, const char* text = 0); |
74 | }; |
75 | |
76 | |
77 | } // namespace Poco |
78 | |
79 | |
80 | // |
81 | // useful macros (these automatically supply line number and file name) |
82 | // |
83 | #if defined(__KLOCWORK__) || defined(__clang_analyzer__) |
84 | |
85 | |
86 | // Short-circuit these macros when under static analysis. |
87 | // Ideally, static analysis tools should understand and reason correctly about |
88 | // noreturn methods such as Bugcheck::bugcheck(). In practice, they don't. |
89 | // Help them by turning these macros into std::abort() as described here: |
90 | // https://developer.klocwork.com/documentation/en/insight/10-1/tuning-cc-analysis#Usingthe__KLOCWORK__macro |
91 | |
92 | #include <cstdlib> // for abort |
93 | #define poco_assert_dbg(cond) do { if (!(cond)) std::abort(); } while (0) |
94 | #define poco_assert_msg_dbg(cond, text) do { if (!(cond)) std::abort(); } while (0) |
95 | #define poco_assert(cond) do { if (!(cond)) std::abort(); } while (0) |
96 | #define poco_assert_msg(cond, text) do { if (!(cond)) std::abort(); } while (0) |
97 | #define poco_check_ptr(ptr) do { if (!(ptr)) std::abort(); } while (0) |
98 | #define poco_bugcheck() do { std::abort(); } while (0) |
99 | #define poco_bugcheck_msg(msg) do { std::abort(); } while (0) |
100 | |
101 | |
102 | #else // defined(__KLOCWORK__) || defined(__clang_analyzer__) |
103 | |
104 | |
105 | #if defined(_DEBUG) |
106 | #define poco_assert_dbg(cond) \ |
107 | if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__); else (void) 0 |
108 | |
109 | #define poco_assert_msg_dbg(cond, text) \ |
110 | if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__, text); else (void) 0 |
111 | #else |
112 | #define poco_assert_msg_dbg(cond, text) |
113 | #define poco_assert_dbg(cond) |
114 | #endif |
115 | |
116 | |
117 | #define poco_assert(cond) \ |
118 | if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__); else (void) 0 |
119 | |
120 | |
121 | #define poco_assert_msg(cond, text) \ |
122 | if (!(cond)) Poco::Bugcheck::assertion(#cond, __FILE__, __LINE__, text); else (void) 0 |
123 | |
124 | |
125 | #define poco_check_ptr(ptr) \ |
126 | if (!(ptr)) Poco::Bugcheck::nullPointer(#ptr, __FILE__, __LINE__); else (void) 0 |
127 | |
128 | |
129 | #define poco_bugcheck() \ |
130 | Poco::Bugcheck::bugcheck(__FILE__, __LINE__) |
131 | |
132 | |
133 | #define poco_bugcheck_msg(msg) \ |
134 | Poco::Bugcheck::bugcheck(msg, __FILE__, __LINE__) |
135 | |
136 | |
137 | #endif // defined(__KLOCWORK__) || defined(__clang_analyzer__) |
138 | |
139 | |
140 | #define poco_unexpected() \ |
141 | Poco::Bugcheck::unexpected(__FILE__, __LINE__); |
142 | |
143 | |
144 | #define poco_debugger() \ |
145 | Poco::Bugcheck::debugger(__FILE__, __LINE__) |
146 | |
147 | |
148 | #define poco_debugger_msg(msg) \ |
149 | Poco::Bugcheck::debugger(msg, __FILE__, __LINE__) |
150 | |
151 | |
152 | #if defined(_DEBUG) |
153 | # define poco_stdout_dbg(outstr) \ |
154 | std::cout << __FILE__ << '(' << std::dec << __LINE__ << "):" << outstr << std::endl; |
155 | #else |
156 | # define poco_stdout_dbg(outstr) |
157 | #endif |
158 | |
159 | |
160 | #if defined(_DEBUG) |
161 | # define poco_stderr_dbg(outstr) \ |
162 | std::cerr << __FILE__ << '(' << std::dec << __LINE__ << "):" << outstr << std::endl; |
163 | #else |
164 | # define poco_stderr_dbg(outstr) |
165 | #endif |
166 | |
167 | |
168 | // |
169 | // poco_static_assert |
170 | // |
171 | // The following was ported from <boost/static_assert.hpp> |
172 | // |
173 | |
174 | |
175 | template <bool x> |
176 | struct POCO_STATIC_ASSERTION_FAILURE; |
177 | |
178 | |
179 | template <> |
180 | struct POCO_STATIC_ASSERTION_FAILURE<true> |
181 | { |
182 | enum |
183 | { |
184 | value = 1 |
185 | }; |
186 | }; |
187 | |
188 | |
189 | template <int x> |
190 | struct poco_static_assert_test |
191 | { |
192 | }; |
193 | |
194 | |
195 | #if defined(__GNUC__) && (__GNUC__ == 3) && ((__GNUC_MINOR__ == 3) || (__GNUC_MINOR__ == 4)) |
196 | #define poco_static_assert(B) \ |
197 | typedef char POCO_JOIN(poco_static_assert_typedef_, __LINE__) \ |
198 | [POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>::value] |
199 | #else |
200 | #define poco_static_assert(B) \ |
201 | typedef poco_static_assert_test<sizeof(POCO_STATIC_ASSERTION_FAILURE<(bool) (B)>)> \ |
202 | POCO_JOIN(poco_static_assert_typedef_, __LINE__) POCO_UNUSED |
203 | #endif |
204 | |
205 | |
206 | #endif // Foundation_Bugcheck_INCLUDED |
207 | |