|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef nsDebug_h___ |
|
7 #define nsDebug_h___ |
|
8 |
|
9 #include "nscore.h" |
|
10 #include "nsError.h" |
|
11 |
|
12 #include "nsXPCOM.h" |
|
13 #include "mozilla/Assertions.h" |
|
14 #include "mozilla/Likely.h" |
|
15 #include <stdarg.h> |
|
16 |
|
17 #ifdef DEBUG |
|
18 #include "prprf.h" |
|
19 #endif |
|
20 |
|
21 /** |
|
22 * Warn if the given condition is true. The condition is evaluated in both |
|
23 * release and debug builds, and the result is an expression which can be |
|
24 * used in subsequent expressions, such as: |
|
25 * |
|
26 * if (NS_WARN_IF(NS_FAILED(rv)) |
|
27 * return rv; |
|
28 * |
|
29 * This explicit warning and return is preferred to the NS_ENSURE_* macros |
|
30 * which hide the warning and the return control flow. |
|
31 * |
|
32 * @note This is C++-only |
|
33 */ |
|
34 #ifdef __cplusplus |
|
35 #ifdef DEBUG |
|
36 inline bool NS_warn_if_impl(bool condition, const char* expr, const char* file, |
|
37 int32_t line) |
|
38 { |
|
39 if (MOZ_UNLIKELY(condition)) { |
|
40 NS_DebugBreak(NS_DEBUG_WARNING, nullptr, expr, file, line); |
|
41 } |
|
42 return condition; |
|
43 } |
|
44 #define NS_WARN_IF(condition) \ |
|
45 NS_warn_if_impl(condition, #condition, __FILE__, __LINE__) |
|
46 #else |
|
47 #define NS_WARN_IF(condition) (bool)(condition) |
|
48 #endif |
|
49 #endif |
|
50 |
|
51 /** |
|
52 * Abort the execution of the program if the expression evaluates to |
|
53 * false. |
|
54 * |
|
55 * There is no status value returned from the macro. |
|
56 * |
|
57 * Note that the non-debug version of this macro does <b>not</b> |
|
58 * evaluate the expression argument. Hence side effect statements |
|
59 * as arguments to the macro will yield improper execution in a |
|
60 * non-debug build. For example: |
|
61 * |
|
62 * NS_ABORT_IF_FALSE(0 == foo++, "yikes foo should be zero"); |
|
63 * |
|
64 * Note also that the non-debug version of this macro does <b>not</b> |
|
65 * evaluate the message argument. |
|
66 */ |
|
67 #ifdef DEBUG |
|
68 #define NS_ABORT_IF_FALSE(_expr, _msg) \ |
|
69 do { \ |
|
70 if (!(_expr)) { \ |
|
71 NS_DebugBreak(NS_DEBUG_ABORT, _msg, #_expr, __FILE__, __LINE__); \ |
|
72 } \ |
|
73 } while(0) |
|
74 #else |
|
75 #define NS_ABORT_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) |
|
76 #endif |
|
77 |
|
78 /** |
|
79 * Warn if a given condition is false. |
|
80 * |
|
81 * Program execution continues past the usage of this macro. |
|
82 * |
|
83 * Note also that the non-debug version of this macro does <b>not</b> |
|
84 * evaluate the message argument. |
|
85 */ |
|
86 #ifdef DEBUG |
|
87 #define NS_WARN_IF_FALSE(_expr,_msg) \ |
|
88 do { \ |
|
89 if (!(_expr)) { \ |
|
90 NS_DebugBreak(NS_DEBUG_WARNING, _msg, #_expr, __FILE__, __LINE__); \ |
|
91 } \ |
|
92 } while(0) |
|
93 #else |
|
94 #define NS_WARN_IF_FALSE(_expr, _msg) do { /* nothing */ } while(0) |
|
95 #endif |
|
96 |
|
97 |
|
98 /** |
|
99 * Test an assertion for truth. If the expression is not true then |
|
100 * trigger a program failure. |
|
101 * |
|
102 * Note that the non-debug version of this macro does <b>not</b> |
|
103 * evaluate the message argument. |
|
104 */ |
|
105 #ifdef DEBUG |
|
106 #define NS_ASSERTION(expr, str) \ |
|
107 do { \ |
|
108 if (!(expr)) { \ |
|
109 NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ |
|
110 } \ |
|
111 } while(0) |
|
112 #else |
|
113 #define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) |
|
114 #endif |
|
115 |
|
116 /** |
|
117 * NS_PRECONDITION/POSTCONDITION are synonyms for NS_ASSERTION. |
|
118 */ |
|
119 #define NS_PRECONDITION(expr, str) NS_ASSERTION(expr, str) |
|
120 #define NS_POSTCONDITION(expr, str) NS_ASSERTION(expr, str) |
|
121 |
|
122 /** |
|
123 * This macros triggers a program failure if executed. It indicates that |
|
124 * an attempt was made to execute some unimplemented functionality. |
|
125 */ |
|
126 #ifdef DEBUG |
|
127 #define NS_NOTYETIMPLEMENTED(str) \ |
|
128 NS_DebugBreak(NS_DEBUG_ASSERTION, str, "NotYetImplemented", __FILE__, __LINE__) |
|
129 #else |
|
130 #define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0) |
|
131 #endif |
|
132 |
|
133 /** |
|
134 * This macros triggers a program failure if executed. It indicates that |
|
135 * an attempt was made to execute a codepath which should not be reachable. |
|
136 */ |
|
137 #ifdef DEBUG |
|
138 #define NS_NOTREACHED(str) \ |
|
139 NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Not Reached", __FILE__, __LINE__) |
|
140 #else |
|
141 #define NS_NOTREACHED(str) do { /* nothing */ } while(0) |
|
142 #endif |
|
143 |
|
144 /** |
|
145 * Log an error message. |
|
146 */ |
|
147 #ifdef DEBUG |
|
148 #define NS_ERROR(str) \ |
|
149 NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Error", __FILE__, __LINE__) |
|
150 #else |
|
151 #define NS_ERROR(str) do { /* nothing */ } while(0) |
|
152 #endif |
|
153 |
|
154 /** |
|
155 * Log a warning message. |
|
156 */ |
|
157 #ifdef DEBUG |
|
158 #define NS_WARNING(str) \ |
|
159 NS_DebugBreak(NS_DEBUG_WARNING, str, nullptr, __FILE__, __LINE__) |
|
160 #else |
|
161 #define NS_WARNING(str) do { /* nothing */ } while(0) |
|
162 #endif |
|
163 |
|
164 /** |
|
165 * Trigger an debug-only abort. |
|
166 * |
|
167 * @see NS_RUNTIMEABORT for release-mode asserts. |
|
168 */ |
|
169 #ifdef DEBUG |
|
170 #define NS_ABORT() \ |
|
171 NS_DebugBreak(NS_DEBUG_ABORT, nullptr, nullptr, __FILE__, __LINE__) |
|
172 #else |
|
173 #define NS_ABORT() do { /* nothing */ } while(0) |
|
174 #endif |
|
175 |
|
176 /** |
|
177 * Trigger a debugger breakpoint, only in debug builds. |
|
178 */ |
|
179 #ifdef DEBUG |
|
180 #define NS_BREAK() \ |
|
181 NS_DebugBreak(NS_DEBUG_BREAK, nullptr, nullptr, __FILE__, __LINE__) |
|
182 #else |
|
183 #define NS_BREAK() do { /* nothing */ } while(0) |
|
184 #endif |
|
185 |
|
186 /****************************************************************************** |
|
187 ** Macros for static assertions. These are used by the sixgill tool. |
|
188 ** When the tool is not running these macros are no-ops. |
|
189 ******************************************************************************/ |
|
190 |
|
191 /* Avoid name collision if included with other headers defining annotations. */ |
|
192 #ifndef HAVE_STATIC_ANNOTATIONS |
|
193 #define HAVE_STATIC_ANNOTATIONS |
|
194 |
|
195 #ifdef XGILL_PLUGIN |
|
196 |
|
197 #define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) |
|
198 #define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) |
|
199 #define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) |
|
200 #define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) |
|
201 #define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) |
|
202 #define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) |
|
203 |
|
204 /* Used to make identifiers for assert/assume annotations in a function. */ |
|
205 #define STATIC_PASTE2(X,Y) X ## Y |
|
206 #define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) |
|
207 |
|
208 #define STATIC_ASSERT(COND) \ |
|
209 do { \ |
|
210 __attribute__((assert_static(#COND), unused)) \ |
|
211 int STATIC_PASTE1(assert_static_, __COUNTER__); \ |
|
212 } while(0) |
|
213 |
|
214 #define STATIC_ASSUME(COND) \ |
|
215 do { \ |
|
216 __attribute__((assume_static(#COND), unused)) \ |
|
217 int STATIC_PASTE1(assume_static_, __COUNTER__); \ |
|
218 } while(0) |
|
219 |
|
220 #define STATIC_ASSERT_RUNTIME(COND) \ |
|
221 do { \ |
|
222 __attribute__((assert_static_runtime(#COND), unused)) \ |
|
223 int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ |
|
224 } while(0) |
|
225 |
|
226 #else /* XGILL_PLUGIN */ |
|
227 |
|
228 #define STATIC_PRECONDITION(COND) /* nothing */ |
|
229 #define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ |
|
230 #define STATIC_POSTCONDITION(COND) /* nothing */ |
|
231 #define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ |
|
232 #define STATIC_INVARIANT(COND) /* nothing */ |
|
233 #define STATIC_INVARIANT_ASSUME(COND) /* nothing */ |
|
234 |
|
235 #define STATIC_ASSERT(COND) do { /* nothing */ } while(0) |
|
236 #define STATIC_ASSUME(COND) do { /* nothing */ } while(0) |
|
237 #define STATIC_ASSERT_RUNTIME(COND) do { /* nothing */ } while(0) |
|
238 |
|
239 #endif /* XGILL_PLUGIN */ |
|
240 |
|
241 #define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) |
|
242 |
|
243 #endif /* HAVE_STATIC_ANNOTATIONS */ |
|
244 |
|
245 #ifdef XGILL_PLUGIN |
|
246 |
|
247 /* Redefine runtime assertion macros to perform static assertions, for both |
|
248 * debug and release builds. Don't include the original runtime assertions; |
|
249 * this ensures the tool will consider cases where the assertion fails. */ |
|
250 |
|
251 #undef NS_PRECONDITION |
|
252 #undef NS_ASSERTION |
|
253 #undef NS_POSTCONDITION |
|
254 |
|
255 #define NS_PRECONDITION(expr, str) STATIC_ASSERT_RUNTIME(expr) |
|
256 #define NS_ASSERTION(expr, str) STATIC_ASSERT_RUNTIME(expr) |
|
257 #define NS_POSTCONDITION(expr, str) STATIC_ASSERT_RUNTIME(expr) |
|
258 |
|
259 #endif /* XGILL_PLUGIN */ |
|
260 |
|
261 /****************************************************************************** |
|
262 ** Macros for terminating execution when an unrecoverable condition is |
|
263 ** reached. These need to be compiled regardless of the DEBUG flag. |
|
264 ******************************************************************************/ |
|
265 |
|
266 /** |
|
267 * Terminate execution <i>immediately</i>, and if possible on the current |
|
268 * platform, in such a way that execution can't be continued by other |
|
269 * code (e.g., by intercepting a signal). |
|
270 */ |
|
271 #define NS_RUNTIMEABORT(msg) \ |
|
272 NS_DebugBreak(NS_DEBUG_ABORT, msg, nullptr, __FILE__, __LINE__) |
|
273 |
|
274 |
|
275 /* Macros for checking the trueness of an expression passed in within an |
|
276 * interface implementation. These need to be compiled regardless of the |
|
277 * DEBUG flag. New code should use NS_WARN_IF(condition) instead! |
|
278 * @status deprecated |
|
279 */ |
|
280 |
|
281 #define NS_ENSURE_TRUE(x, ret) \ |
|
282 do { \ |
|
283 if (MOZ_UNLIKELY(!(x))) { \ |
|
284 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
|
285 return ret; \ |
|
286 } \ |
|
287 } while(0) |
|
288 |
|
289 #define NS_ENSURE_FALSE(x, ret) \ |
|
290 NS_ENSURE_TRUE(!(x), ret) |
|
291 |
|
292 #define NS_ENSURE_TRUE_VOID(x) \ |
|
293 do { \ |
|
294 if (MOZ_UNLIKELY(!(x))) { \ |
|
295 NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
|
296 return; \ |
|
297 } \ |
|
298 } while(0) |
|
299 |
|
300 #define NS_ENSURE_FALSE_VOID(x) \ |
|
301 NS_ENSURE_TRUE_VOID(!(x)) |
|
302 |
|
303 /****************************************************************************** |
|
304 ** Macros for checking results |
|
305 ******************************************************************************/ |
|
306 |
|
307 #if defined(DEBUG) && !defined(XPCOM_GLUE_AVOID_NSPR) |
|
308 |
|
309 #define NS_ENSURE_SUCCESS_BODY(res, ret) \ |
|
310 char *msg = PR_smprintf("NS_ENSURE_SUCCESS(%s, %s) failed with " \ |
|
311 "result 0x%X", #res, #ret, __rv); \ |
|
312 NS_WARNING(msg); \ |
|
313 PR_smprintf_free(msg); |
|
314 |
|
315 #define NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
|
316 char *msg = PR_smprintf("NS_ENSURE_SUCCESS_VOID(%s) failed with " \ |
|
317 "result 0x%X", #res, __rv); \ |
|
318 NS_WARNING(msg); \ |
|
319 PR_smprintf_free(msg); |
|
320 |
|
321 #else |
|
322 |
|
323 #define NS_ENSURE_SUCCESS_BODY(res, ret) \ |
|
324 NS_WARNING("NS_ENSURE_SUCCESS(" #res ", " #ret ") failed"); |
|
325 |
|
326 #define NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
|
327 NS_WARNING("NS_ENSURE_SUCCESS_VOID(" #res ") failed"); |
|
328 |
|
329 #endif |
|
330 |
|
331 #define NS_ENSURE_SUCCESS(res, ret) \ |
|
332 do { \ |
|
333 nsresult __rv = res; /* Don't evaluate |res| more than once */ \ |
|
334 if (NS_FAILED(__rv)) { \ |
|
335 NS_ENSURE_SUCCESS_BODY(res, ret) \ |
|
336 return ret; \ |
|
337 } \ |
|
338 } while(0) |
|
339 |
|
340 #define NS_ENSURE_SUCCESS_VOID(res) \ |
|
341 do { \ |
|
342 nsresult __rv = res; \ |
|
343 if (NS_FAILED(__rv)) { \ |
|
344 NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
|
345 return; \ |
|
346 } \ |
|
347 } while(0) |
|
348 |
|
349 /****************************************************************************** |
|
350 ** Macros for checking state and arguments upon entering interface boundaries |
|
351 ******************************************************************************/ |
|
352 |
|
353 #define NS_ENSURE_ARG(arg) \ |
|
354 NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_ARG) |
|
355 |
|
356 #define NS_ENSURE_ARG_POINTER(arg) \ |
|
357 NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_POINTER) |
|
358 |
|
359 #define NS_ENSURE_ARG_MIN(arg, min) \ |
|
360 NS_ENSURE_TRUE((arg) >= min, NS_ERROR_INVALID_ARG) |
|
361 |
|
362 #define NS_ENSURE_ARG_MAX(arg, max) \ |
|
363 NS_ENSURE_TRUE((arg) <= max, NS_ERROR_INVALID_ARG) |
|
364 |
|
365 #define NS_ENSURE_ARG_RANGE(arg, min, max) \ |
|
366 NS_ENSURE_TRUE(((arg) >= min) && ((arg) <= max), NS_ERROR_INVALID_ARG) |
|
367 |
|
368 #define NS_ENSURE_STATE(state) \ |
|
369 NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED) |
|
370 |
|
371 #define NS_ENSURE_NO_AGGREGATION(outer) \ |
|
372 NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) |
|
373 |
|
374 /*****************************************************************************/ |
|
375 |
|
376 #ifdef XPCOM_GLUE |
|
377 #define NS_CheckThreadSafe(owningThread, msg) |
|
378 #else |
|
379 #define NS_CheckThreadSafe(owningThread, msg) \ |
|
380 if (MOZ_UNLIKELY(owningThread != PR_GetCurrentThread())) { \ |
|
381 MOZ_CRASH(msg); \ |
|
382 } |
|
383 #endif |
|
384 |
|
385 #ifdef MOZILLA_INTERNAL_API |
|
386 void NS_ABORT_OOM(size_t size); |
|
387 #else |
|
388 inline void NS_ABORT_OOM(size_t) |
|
389 { |
|
390 MOZ_CRASH(); |
|
391 } |
|
392 #endif |
|
393 |
|
394 /* When compiling the XPCOM Glue on Windows, we pretend that it's going to |
|
395 * be linked with a static CRT (-MT) even when it's not. This means that we |
|
396 * cannot link to data exports from the CRT, only function exports. So, |
|
397 * instead of referencing "stderr" directly, use fdopen. |
|
398 */ |
|
399 #ifdef __cplusplus |
|
400 extern "C" { |
|
401 #endif |
|
402 |
|
403 NS_COM_GLUE void |
|
404 printf_stderr(const char *fmt, ...); |
|
405 |
|
406 NS_COM_GLUE void |
|
407 vprintf_stderr(const char *fmt, va_list args); |
|
408 |
|
409 // fprintf with special handling for stderr to print to the console |
|
410 NS_COM_GLUE void |
|
411 fprintf_stderr(FILE* aFile, const char *fmt, ...); |
|
412 |
|
413 #ifdef __cplusplus |
|
414 } |
|
415 #endif |
|
416 |
|
417 #endif /* nsDebug_h___ */ |