Line data Source code
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 154869 : inline MOZ_MUST_USE bool NS_warn_if_impl(bool aCondition, const char* aExpr,
53 : const char* aFile, int32_t aLine)
54 : {
55 154869 : if (MOZ_UNLIKELY(aCondition)) {
56 7 : NS_DebugBreak(NS_DEBUG_WARNING, nullptr, aExpr, aFile, aLine);
57 : }
58 154869 : return aCondition;
59 : }
60 : #define NS_WARN_IF(condition) \
61 : NS_warn_if_impl(condition, #condition, __FILE__, __LINE__)
62 : #else
63 : #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(0)
83 : #else
84 : #define NS_WARNING_ASSERTION(_expr, _msg) do { /* nothing */ } while(0)
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 0 : inline void MOZ_PretendNoReturn()
96 0 : 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 : #define NS_ASSERTION(expr, str) do { /* nothing */ } while(0)
106 : #endif
107 :
108 : /**
109 : * NS_PRECONDITION/POSTCONDITION are synonyms for NS_ASSERTION.
110 : */
111 : #define NS_PRECONDITION(expr, str) NS_ASSERTION(expr, str)
112 : #define NS_POSTCONDITION(expr, str) NS_ASSERTION(expr, str)
113 :
114 : /**
115 : * This macros triggers a program failure if executed. It indicates that
116 : * an attempt was made to execute some unimplemented functionality.
117 : */
118 : #ifdef DEBUG
119 : #define NS_NOTYETIMPLEMENTED(str) \
120 : do { \
121 : NS_DebugBreak(NS_DEBUG_ASSERTION, str, "NotYetImplemented", __FILE__, __LINE__); \
122 : MOZ_PretendNoReturn(); \
123 : } while(0)
124 : #else
125 : #define NS_NOTYETIMPLEMENTED(str) do { /* nothing */ } while(0)
126 : #endif
127 :
128 : /**
129 : * This macros triggers a program failure if executed. It indicates that
130 : * an attempt was made to execute a codepath which should not be reachable.
131 : */
132 : #ifdef DEBUG
133 : #define NS_NOTREACHED(str) \
134 : do { \
135 : NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Not Reached", __FILE__, __LINE__); \
136 : MOZ_PretendNoReturn(); \
137 : } while(0)
138 : #else
139 : #define NS_NOTREACHED(str) do { /* nothing */ } while(0)
140 : #endif
141 :
142 : /**
143 : * Log an error message.
144 : */
145 : #ifdef DEBUG
146 : #define NS_ERROR(str) \
147 : do { \
148 : NS_DebugBreak(NS_DEBUG_ASSERTION, str, "Error", __FILE__, __LINE__); \
149 : MOZ_PretendNoReturn(); \
150 : } while(0)
151 : #else
152 : #define NS_ERROR(str) do { /* nothing */ } while(0)
153 : #endif
154 :
155 : /**
156 : * Log a warning message.
157 : */
158 : #ifdef DEBUG
159 : #define NS_WARNING(str) \
160 : NS_DebugBreak(NS_DEBUG_WARNING, str, nullptr, __FILE__, __LINE__)
161 : #else
162 : #define NS_WARNING(str) do { /* nothing */ } while(0)
163 : #endif
164 :
165 : /**
166 : * Trigger an debug-only abort.
167 : *
168 : * @see NS_RUNTIMEABORT for release-mode asserts.
169 : */
170 : #ifdef DEBUG
171 : #define NS_ABORT() \
172 : do { \
173 : NS_DebugBreak(NS_DEBUG_ABORT, nullptr, nullptr, __FILE__, __LINE__); \
174 : MOZ_PretendNoReturn(); \
175 : } while(0)
176 : #else
177 : #define NS_ABORT() do { /* nothing */ } while(0)
178 : #endif
179 :
180 : /**
181 : * Trigger a debugger breakpoint, only in debug builds.
182 : */
183 : #ifdef DEBUG
184 : #define NS_BREAK() \
185 : do { \
186 : NS_DebugBreak(NS_DEBUG_BREAK, nullptr, nullptr, __FILE__, __LINE__); \
187 : MOZ_PretendNoReturn(); \
188 : } while(0)
189 : #else
190 : #define NS_BREAK() do { /* nothing */ } while(0)
191 : #endif
192 :
193 : /******************************************************************************
194 : ** Macros for static assertions. These are used by the sixgill tool.
195 : ** When the tool is not running these macros are no-ops.
196 : ******************************************************************************/
197 :
198 : /* Avoid name collision if included with other headers defining annotations. */
199 : #ifndef HAVE_STATIC_ANNOTATIONS
200 : #define HAVE_STATIC_ANNOTATIONS
201 :
202 : #ifdef XGILL_PLUGIN
203 :
204 : #define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
205 : #define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
206 : #define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
207 : #define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
208 : #define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
209 : #define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
210 :
211 : /* Used to make identifiers for assert/assume annotations in a function. */
212 : #define STATIC_PASTE2(X,Y) X ## Y
213 : #define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
214 :
215 : #define STATIC_ASSUME(COND) \
216 : do { \
217 : __attribute__((assume_static(#COND), unused)) \
218 : int STATIC_PASTE1(assume_static_, __COUNTER__); \
219 : } while(0)
220 :
221 : #define STATIC_ASSERT_RUNTIME(COND) \
222 : do { \
223 : __attribute__((assert_static_runtime(#COND), unused)) \
224 : int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
225 : } while(0)
226 :
227 : #else /* XGILL_PLUGIN */
228 :
229 : #define STATIC_PRECONDITION(COND) /* nothing */
230 : #define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
231 : #define STATIC_POSTCONDITION(COND) /* nothing */
232 : #define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
233 : #define STATIC_INVARIANT(COND) /* nothing */
234 : #define STATIC_INVARIANT_ASSUME(COND) /* nothing */
235 :
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 : /******************************************************************************
246 : ** Macros for terminating execution when an unrecoverable condition is
247 : ** reached. These need to be compiled regardless of the DEBUG flag.
248 : ******************************************************************************/
249 :
250 : /**
251 : * Terminate execution <i>immediately</i>, and if possible on the current
252 : * platform, in such a way that execution can't be continued by other
253 : * code (e.g., by intercepting a signal).
254 : */
255 : #define NS_RUNTIMEABORT(msg) \
256 : NS_DebugBreak(NS_DEBUG_ABORT, msg, nullptr, __FILE__, __LINE__)
257 :
258 :
259 : /* Macros for checking the trueness of an expression passed in within an
260 : * interface implementation. These need to be compiled regardless of the
261 : * DEBUG flag. New code should use NS_WARN_IF(condition) instead!
262 : * @status deprecated
263 : */
264 :
265 : #define NS_ENSURE_TRUE(x, ret) \
266 : do { \
267 : if (MOZ_UNLIKELY(!(x))) { \
268 : NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
269 : return ret; \
270 : } \
271 : } while(0)
272 :
273 : #define NS_ENSURE_FALSE(x, ret) \
274 : NS_ENSURE_TRUE(!(x), ret)
275 :
276 : #define NS_ENSURE_TRUE_VOID(x) \
277 : do { \
278 : if (MOZ_UNLIKELY(!(x))) { \
279 : NS_WARNING("NS_ENSURE_TRUE(" #x ") failed"); \
280 : return; \
281 : } \
282 : } while(0)
283 :
284 : #define NS_ENSURE_FALSE_VOID(x) \
285 : NS_ENSURE_TRUE_VOID(!(x))
286 :
287 : /******************************************************************************
288 : ** Macros for checking results
289 : ******************************************************************************/
290 :
291 : #if defined(DEBUG) && !defined(XPCOM_GLUE_AVOID_NSPR)
292 :
293 : #define NS_ENSURE_SUCCESS_BODY(res, ret) \
294 : mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS(%s, %s) failed with " \
295 : "result 0x%" PRIX32, #res, #ret, \
296 : static_cast<uint32_t>(__rv)); \
297 : NS_WARNING(msg.get());
298 :
299 : #define NS_ENSURE_SUCCESS_BODY_VOID(res) \
300 : mozilla::SmprintfPointer msg = mozilla::Smprintf("NS_ENSURE_SUCCESS_VOID(%s) failed with " \
301 : "result 0x%" PRIX32, #res, \
302 : static_cast<uint32_t>(__rv)); \
303 : NS_WARNING(msg.get());
304 :
305 : #else
306 :
307 : #define NS_ENSURE_SUCCESS_BODY(res, ret) \
308 : NS_WARNING("NS_ENSURE_SUCCESS(" #res ", " #ret ") failed");
309 :
310 : #define NS_ENSURE_SUCCESS_BODY_VOID(res) \
311 : NS_WARNING("NS_ENSURE_SUCCESS_VOID(" #res ") failed");
312 :
313 : #endif
314 :
315 : #define NS_ENSURE_SUCCESS(res, ret) \
316 : do { \
317 : nsresult __rv = res; /* Don't evaluate |res| more than once */ \
318 : if (NS_FAILED(__rv)) { \
319 : NS_ENSURE_SUCCESS_BODY(res, ret) \
320 : return ret; \
321 : } \
322 : } while(0)
323 :
324 : #define NS_ENSURE_SUCCESS_VOID(res) \
325 : do { \
326 : nsresult __rv = res; \
327 : if (NS_FAILED(__rv)) { \
328 : NS_ENSURE_SUCCESS_BODY_VOID(res) \
329 : return; \
330 : } \
331 : } while(0)
332 :
333 : /******************************************************************************
334 : ** Macros for checking state and arguments upon entering interface boundaries
335 : ******************************************************************************/
336 :
337 : #define NS_ENSURE_ARG(arg) \
338 : NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_ARG)
339 :
340 : #define NS_ENSURE_ARG_POINTER(arg) \
341 : NS_ENSURE_TRUE(arg, NS_ERROR_INVALID_POINTER)
342 :
343 : #define NS_ENSURE_ARG_MIN(arg, min) \
344 : NS_ENSURE_TRUE((arg) >= min, NS_ERROR_INVALID_ARG)
345 :
346 : #define NS_ENSURE_ARG_MAX(arg, max) \
347 : NS_ENSURE_TRUE((arg) <= max, NS_ERROR_INVALID_ARG)
348 :
349 : #define NS_ENSURE_ARG_RANGE(arg, min, max) \
350 : NS_ENSURE_TRUE(((arg) >= min) && ((arg) <= max), NS_ERROR_INVALID_ARG)
351 :
352 : #define NS_ENSURE_STATE(state) \
353 : NS_ENSURE_TRUE(state, NS_ERROR_UNEXPECTED)
354 :
355 : #define NS_ENSURE_NO_AGGREGATION(outer) \
356 : NS_ENSURE_FALSE(outer, NS_ERROR_NO_AGGREGATION)
357 :
358 : /*****************************************************************************/
359 :
360 : #if (defined(DEBUG) || (defined(NIGHTLY_BUILD) && !defined(MOZ_PROFILING))) && !defined(XPCOM_GLUE_AVOID_NSPR)
361 : #define MOZ_THREAD_SAFETY_OWNERSHIP_CHECKS_SUPPORTED 1
362 : #endif
363 :
364 : #ifdef MOZILLA_INTERNAL_API
365 : void NS_ABORT_OOM(size_t aSize);
366 : #else
367 : inline void NS_ABORT_OOM(size_t)
368 : {
369 : MOZ_CRASH();
370 : }
371 : #endif
372 :
373 : /* When compiling the XPCOM Glue on Windows, we pretend that it's going to
374 : * be linked with a static CRT (-MT) even when it's not. This means that we
375 : * cannot link to data exports from the CRT, only function exports. So,
376 : * instead of referencing "stderr" directly, use fdopen.
377 : */
378 : #ifdef __cplusplus
379 : extern "C" {
380 : #endif
381 :
382 : /**
383 : * printf_stderr(...) is much like fprintf(stderr, ...), except that:
384 : * - on Android and Firefox OS, *instead* of printing to stderr, it
385 : * prints to logcat. (Newlines in the string lead to multiple lines
386 : * of logcat, but each function call implicitly completes a line even
387 : * if the string does not end with a newline.)
388 : * - on Windows, if a debugger is present, it calls OutputDebugString
389 : * in *addition* to writing to stderr
390 : */
391 : void printf_stderr(const char* aFmt, ...) MOZ_FORMAT_PRINTF(1, 2);
392 :
393 : /**
394 : * Same as printf_stderr, but taking va_list instead of varargs
395 : */
396 : void vprintf_stderr(const char* aFmt, va_list aArgs) MOZ_FORMAT_PRINTF(1, 0);
397 :
398 : /**
399 : * fprintf_stderr is like fprintf, except that if its file argument
400 : * is stderr, it invokes printf_stderr instead.
401 : *
402 : * This is useful for general debugging code that logs information to a
403 : * file, but that you would like to be useful on Android and Firefox OS.
404 : * If you use fprintf_stderr instead of fprintf in such debugging code,
405 : * then callers can pass stderr to get logging that works on Android and
406 : * Firefox OS (and also the other side-effects of using printf_stderr).
407 : *
408 : * Code that is structured this way needs to be careful not to split a
409 : * line of output across multiple calls to fprintf_stderr, since doing
410 : * so will cause it to appear in multiple lines in logcat output.
411 : * (Producing multiple lines at once is fine.)
412 : */
413 : void fprintf_stderr(FILE* aFile, const char* aFmt, ...) MOZ_FORMAT_PRINTF(2, 3);
414 :
415 : #ifdef __cplusplus
416 : }
417 : #endif
418 :
419 : #endif /* nsDebug_h___ */
|