/src/mozilla-central/xpcom/base/nsDebug.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef nsDebug_h___ |
8 | | #define nsDebug_h___ |
9 | | |
10 | | #include "nscore.h" |
11 | | #include "nsError.h" |
12 | | |
13 | | #include "nsXPCOM.h" |
14 | | #include "mozilla/Assertions.h" |
15 | | #include "mozilla/Likely.h" |
16 | | #include <stdarg.h> |
17 | | |
18 | | #ifdef DEBUG |
19 | | #include "mozilla/IntegerPrintfMacros.h" |
20 | | #include "mozilla/Printf.h" |
21 | | #endif |
22 | | |
23 | | /** |
24 | | * Warn if the given condition is true. The condition is evaluated in both |
25 | | * release and debug builds, and the result is an expression which can be |
26 | | * used in subsequent expressions, such as: |
27 | | * |
28 | | * if (NS_WARN_IF(NS_FAILED(rv)) { |
29 | | * return rv; |
30 | | * } |
31 | | * |
32 | | * This explicit warning and return is preferred to the NS_ENSURE_* macros |
33 | | * which hide the warning and the return control flow. |
34 | | * |
35 | | * This macro can also be used outside of conditions just to issue a warning, |
36 | | * like so: |
37 | | * |
38 | | * Unused << NS_WARN_IF(NS_FAILED(FnWithSideEffects()); |
39 | | * |
40 | | * (The |Unused <<| is necessary because of the MOZ_MUST_USE annotation.) |
41 | | * |
42 | | * However, note that the argument to this macro is evaluated in all builds. If |
43 | | * you just want a warning assertion, it is better to use NS_WARNING_ASSERTION |
44 | | * (which evaluates the condition only in debug builds) like so: |
45 | | * |
46 | | * NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "operation failed"); |
47 | | * |
48 | | * @note This is C++-only |
49 | | */ |
50 | | #ifdef __cplusplus |
51 | | #ifdef DEBUG |
52 | | inline MOZ_MUST_USE bool NS_warn_if_impl(bool aCondition, const char* aExpr, |
53 | | const char* aFile, int32_t aLine) |
54 | | { |
55 | | if (MOZ_UNLIKELY(aCondition)) { |
56 | | NS_DebugBreak(NS_DEBUG_WARNING, nullptr, aExpr, aFile, aLine); |
57 | | } |
58 | | return aCondition; |
59 | | } |
60 | | #define NS_WARN_IF(condition) \ |
61 | | NS_warn_if_impl(condition, #condition, __FILE__, __LINE__) |
62 | | #else |
63 | 592k | #define NS_WARN_IF(condition) (bool)(condition) |
64 | | #endif |
65 | | #endif |
66 | | |
67 | | /** |
68 | | * Test an assertion for truth. If the expression is not true then |
69 | | * emit a warning. |
70 | | * |
71 | | * Program execution continues past the usage of this macro. |
72 | | * |
73 | | * Note also that the non-debug version of this macro does <b>not</b> |
74 | | * evaluate the message argument. |
75 | | */ |
76 | | #ifdef DEBUG |
77 | | #define NS_WARNING_ASSERTION(_expr, _msg) \ |
78 | | do { \ |
79 | | if (!(_expr)) { \ |
80 | | NS_DebugBreak(NS_DEBUG_WARNING, _msg, #_expr, __FILE__, __LINE__); \ |
81 | | } \ |
82 | | } while(false) |
83 | | #else |
84 | 0 | #define NS_WARNING_ASSERTION(_expr, _msg) do { /* nothing */ } while(false) |
85 | | #endif |
86 | | |
87 | | /** |
88 | | * Test an assertion for truth. If the expression is not true then |
89 | | * trigger a program failure. |
90 | | * |
91 | | * Note that the non-debug version of this macro does <b>not</b> |
92 | | * evaluate the message argument. |
93 | | */ |
94 | | #ifdef DEBUG |
95 | | inline void MOZ_PretendNoReturn() |
96 | | MOZ_PRETEND_NORETURN_FOR_STATIC_ANALYSIS {} |
97 | | #define NS_ASSERTION(expr, str) \ |
98 | | do { \ |
99 | | if (!(expr)) { \ |
100 | | NS_DebugBreak(NS_DEBUG_ASSERTION, str, #expr, __FILE__, __LINE__); \ |
101 | | MOZ_PretendNoReturn(); \ |
102 | | } \ |
103 | | } while(0) |
104 | | #else |
105 | 5.04M | #define NS_ASSERTION(expr, str) do { /* nothing */ } while(0) |
106 | | #endif |
107 | | |
108 | | /** |
109 | | * Log an error message. |
110 | | */ |
111 | | #ifdef DEBUG |
112 | | #define NS_ERROR(str) \ |
113 | | do { \ |
114 | | NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Error", __FILE__, __LINE__); \ |
115 | | MOZ_PretendNoReturn(); \ |
116 | | } while(0) |
117 | | #else |
118 | 0 | #define NS_ERROR(str) do { /* nothing */ } while(0) |
119 | | #endif |
120 | | |
121 | | /** |
122 | | * Log a warning message. |
123 | | */ |
124 | | #ifdef DEBUG |
125 | | #define NS_WARNING(str) \ |
126 | | NS_DebugBreak(NS_DEBUG_WARNING, str, nullptr, __FILE__, __LINE__) |
127 | | #else |
128 | 0 | #define NS_WARNING(str) do { /* nothing */ } while(0) |
129 | | #endif |
130 | | |
131 | | /** |
132 | | * Trigger a debugger breakpoint, only in debug builds. |
133 | | */ |
134 | | #ifdef DEBUG |
135 | | #define NS_BREAK() \ |
136 | | do { \ |
137 | | NS_DebugBreak(NS_DEBUG_BREAK, nullptr, nullptr, __FILE__, __LINE__); \ |
138 | | MOZ_PretendNoReturn(); \ |
139 | | } while(0) |
140 | | #else |
141 | | #define NS_BREAK() do { /* nothing */ } while(0) |
142 | | #endif |
143 | | |
144 | | /****************************************************************************** |
145 | | ** Macros for static assertions. These are used by the sixgill tool. |
146 | | ** When the tool is not running these macros are no-ops. |
147 | | ******************************************************************************/ |
148 | | |
149 | | /* Avoid name collision if included with other headers defining annotations. */ |
150 | | #ifndef HAVE_STATIC_ANNOTATIONS |
151 | | #define HAVE_STATIC_ANNOTATIONS |
152 | | |
153 | | #ifdef XGILL_PLUGIN |
154 | | |
155 | | #define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) |
156 | | #define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) |
157 | | #define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) |
158 | | #define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) |
159 | | #define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) |
160 | | #define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) |
161 | | |
162 | | /* Used to make identifiers for assert/assume annotations in a function. */ |
163 | | #define STATIC_PASTE2(X,Y) X ## Y |
164 | | #define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) |
165 | | |
166 | | #define STATIC_ASSUME(COND) \ |
167 | | do { \ |
168 | | __attribute__((assume_static(#COND), unused)) \ |
169 | | int STATIC_PASTE1(assume_static_, __COUNTER__); \ |
170 | | } while(false) |
171 | | |
172 | | #define STATIC_ASSERT_RUNTIME(COND) \ |
173 | | do { \ |
174 | | __attribute__((assert_static_runtime(#COND), unused)) \ |
175 | | int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ |
176 | | } while(false) |
177 | | |
178 | | #else /* XGILL_PLUGIN */ |
179 | | |
180 | | #define STATIC_PRECONDITION(COND) /* nothing */ |
181 | | #define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ |
182 | | #define STATIC_POSTCONDITION(COND) /* nothing */ |
183 | | #define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ |
184 | | #define STATIC_INVARIANT(COND) /* nothing */ |
185 | | #define STATIC_INVARIANT_ASSUME(COND) /* nothing */ |
186 | | |
187 | | #define STATIC_ASSUME(COND) do { /* nothing */ } while(false) |
188 | | #define STATIC_ASSERT_RUNTIME(COND) do { /* nothing */ } while(false) |
189 | | |
190 | | #endif /* XGILL_PLUGIN */ |
191 | | |
192 | | #define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) |
193 | | |
194 | | #endif /* HAVE_STATIC_ANNOTATIONS */ |
195 | | |
196 | | /****************************************************************************** |
197 | | ** Macros for terminating execution when an unrecoverable condition is |
198 | | ** reached. These need to be compiled regardless of the DEBUG flag. |
199 | | ******************************************************************************/ |
200 | | |
201 | | /* Macros for checking the trueness of an expression passed in within an |
202 | | * interface implementation. These need to be compiled regardless of the |
203 | | * DEBUG flag. New code should use NS_WARN_IF(condition) instead! |
204 | | * @status deprecated |
205 | | */ |
206 | | |
207 | | #define NS_ENSURE_TRUE(x, ret) \ |
208 | 6 | do { \ |
209 | 6 | if (MOZ_UNLIKELY(!(x))) { \ |
210 | 0 | NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
211 | 0 | return ret; \ |
212 | 0 | } \ |
213 | 6 | } while(false) |
214 | | |
215 | | #define NS_ENSURE_FALSE(x, ret) \ |
216 | 0 | NS_ENSURE_TRUE(!(x), ret) |
217 | | |
218 | | #define NS_ENSURE_TRUE_VOID(x) \ |
219 | 0 | do { \ |
220 | 0 | if (MOZ_UNLIKELY(!(x))) { \ |
221 | 0 | NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \ |
222 | 0 | return; \ |
223 | 0 | } \ |
224 | 0 | } while(false) |
225 | | |
226 | | #define NS_ENSURE_FALSE_VOID(x) \ |
227 | | NS_ENSURE_TRUE_VOID(!(x)) |
228 | | |
229 | | /****************************************************************************** |
230 | | ** Macros for checking results |
231 | | ******************************************************************************/ |
232 | | |
233 | | #if defined(DEBUG) && !defined(XPCOM_GLUE_AVOID_NSPR) |
234 | | |
235 | | #define NS_ENSURE_SUCCESS_BODY(res, ret) \ |
236 | | mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS(%s, %s) failed with " \ |
237 | | "result 0x%" PRIX32, #res, #ret, \ |
238 | | static_cast<uint32_t>(__rv)); \ |
239 | | NS_WARNING(msg.get()); |
240 | | |
241 | | #define NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
242 | | mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS_VOID(%s) failed with " \ |
243 | | "result 0x%" PRIX32, #res, \ |
244 | | static_cast<uint32_t>(__rv)); \ |
245 | | NS_WARNING(msg.get()); |
246 | | |
247 | | #else |
248 | | |
249 | | #define NS_ENSURE_SUCCESS_BODY(res, ret) \ |
250 | 0 | NS_WARNING("NS_ENSURE_SUCCESS(" #res ", " #ret ") failed"); |
251 | | |
252 | | #define NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
253 | 0 | NS_WARNING("NS_ENSURE_SUCCESS_VOID(" #res ") failed"); |
254 | | |
255 | | #endif |
256 | | |
257 | | #define NS_ENSURE_SUCCESS(res, ret) \ |
258 | 0 | do { \ |
259 | 0 | nsresult __rv = res; /* Don't evaluate |res| more than once */ \ |
260 | 0 | if (NS_FAILED(__rv)) { \ |
261 | 0 | NS_ENSURE_SUCCESS_BODY(res, ret) \ |
262 | 0 | return ret; \ |
263 | 0 | } \ |
264 | 0 | } while(false) |
265 | | |
266 | | #define NS_ENSURE_SUCCESS_VOID(res) \ |
267 | 0 | do { \ |
268 | 0 | nsresult __rv = res; \ |
269 | 0 | if (NS_FAILED(__rv)) { \ |
270 | 0 | NS_ENSURE_SUCCESS_BODY_VOID(res) \ |
271 | 0 | return; \ |
272 | 0 | } \ |
273 | 0 | } while(false) |
274 | | |
275 | | /****************************************************************************** |
276 | | ** Macros for checking state and arguments upon entering interface boundaries |
277 | | ******************************************************************************/ |
278 | | |
279 | | #define NS_ENSURE_ARG(arg) \ |
280 | 0 | NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_ARG) |
281 | | |
282 | | #define NS_ENSURE_ARG_POINTER(arg) \ |
283 | 0 | NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_POINTER) |
284 | | |
285 | | #define NS_ENSURE_ARG_MIN(arg, min) \ |
286 | | NS_ENSURE_TRUE((arg) >= min, NS_ERROR_INVALID_ARG) |
287 | | |
288 | | #define NS_ENSURE_ARG_MAX(arg, max) \ |
289 | | NS_ENSURE_TRUE((arg) <= max, NS_ERROR_INVALID_ARG) |
290 | | |
291 | | #define NS_ENSURE_ARG_RANGE(arg, min, max) \ |
292 | | NS_ENSURE_TRUE(((arg) >= min) && ((arg) <= max), NS_ERROR_INVALID_ARG) |
293 | | |
294 | | #define NS_ENSURE_STATE(state) \ |
295 | 0 | NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED) |
296 | | |
297 | | #define NS_ENSURE_NO_AGGREGATION(outer) \ |
298 | | NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION) |
299 | | |
300 | | /*****************************************************************************/ |
301 | | |
302 | | #if (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) && !defined(XPCOM_GLUE_AVOID_NSPR) |
303 | | #define MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED 1 |
304 | | #endif |
305 | | |
306 | | #ifdef MOZILLA_INTERNAL_API |
307 | | void NS_ABORT_OOM(size_t aSize); |
308 | | #else |
309 | | inline void NS_ABORT_OOM(size_t) |
310 | 0 | { |
311 | 0 | MOZ_CRASH(); |
312 | 0 | } |
313 | | #endif |
314 | | |
315 | | /* When compiling the XPCOM Glue on Windows, we pretend that it's going to |
316 | | * be linked with a static CRT (-MT) even when it's not. This means that we |
317 | | * cannot link to data exports from the CRT, only function exports. So, |
318 | | * instead of referencing "stderr" directly, use fdopen. |
319 | | */ |
320 | | #ifdef __cplusplus |
321 | | extern "C" { |
322 | | #endif |
323 | | |
324 | | /** |
325 | | * printf_stderr(...) is much like fprintf(stderr, ...), except that: |
326 | | * - on Android and Firefox OS, *instead* of printing to stderr, it |
327 | | * prints to logcat. (Newlines in the string lead to multiple lines |
328 | | * of logcat, but each function call implicitly completes a line even |
329 | | * if the string does not end with a newline.) |
330 | | * - on Windows, if a debugger is present, it calls OutputDebugString |
331 | | * in *addition* to writing to stderr |
332 | | */ |
333 | | void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2); |
334 | | |
335 | | /** |
336 | | * Same as printf_stderr, but taking va_list instead of varargs |
337 | | */ |
338 | | void vprintf_stderr(const char* aFmt, va_list aArgs) MOZ_FORMAT_PRINTF(1, 0); |
339 | | |
340 | | /** |
341 | | * fprintf_stderr is like fprintf, except that if its file argument |
342 | | * is stderr, it invokes printf_stderr instead. |
343 | | * |
344 | | * This is useful for general debugging code that logs information to a |
345 | | * file, but that you would like to be useful on Android and Firefox OS. |
346 | | * If you use fprintf_stderr instead of fprintf in such debugging code, |
347 | | * then callers can pass stderr to get logging that works on Android and |
348 | | * Firefox OS (and also the other side-effects of using printf_stderr). |
349 | | * |
350 | | * Code that is structured this way needs to be careful not to split a |
351 | | * line of output across multiple calls to fprintf_stderr, since doing |
352 | | * so will cause it to appear in multiple lines in logcat output. |
353 | | * (Producing multiple lines at once is fine.) |
354 | | */ |
355 | | void fprintf_stderr(FILE* aFile, const char* aFmt, ...) MOZ_FORMAT_PRINTF(2, 3); |
356 | | |
357 | | #ifdef __cplusplus |
358 | | } |
359 | | #endif |
360 | | |
361 | | #endif /* nsDebug_h___ */ |