source: branches/stable/CORE/arb_assert.h

Last change on this file was 17695, checked in by westram, 5 years ago
  • dump stack-trace for assertions (failing from testcode) into compile-log
    • works only if DEBUG=1, UNIT_TESTS=1 and SANITIZE=1|all
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 KB
Line 
1/*  ====================================================================
2
3    File      : arb_assert.h
4    Purpose   : Global assert macro
5
6
7  Coded by Ralf Westram (coder@reallysoft.de) in August 2002
8  Copyright Department of Microbiology (Technical University Munich)
9
10  Visit our web site at: http://www.arb-home.de/
11
12
13  ==================================================================== */
14
15#ifndef ARB_ASSERT_H
16#define ARB_ASSERT_H
17
18// [WhyIncludeHere]
19// need to include all headers needed for unit-tests here [sic]
20// if only included inside test_global.h, developing with active unit-tests
21// will always break non-unit-test-builds.
22
23#ifndef _STDARG_H
24#include <stdarg.h>
25#endif
26#ifndef _STDIO_H
27#include <stdio.h>
28#endif
29#ifndef _STDLIB_H
30#include <stdlib.h>
31#endif
32#ifndef _ERRNO_H
33#include <errno.h>
34#endif
35#ifndef _STRING_H
36#include <string.h>
37#endif
38#ifndef _SIGNAL_H
39#include <signal.h>
40#endif
41
42/* ------------------------------------------------------------
43 * Include arb_simple_assert.h to avoid dependency from CORE library!
44 * ------------------------------------------------------------
45 * available assertion flavors:
46 *
47 * ASSERT_CRASH                 if assert fails debugger stops at assert macro
48 * ASSERT_BACKTRACE_AND_CRASH   like ASSERT_CRASH - with backtrace
49 * ASSERT_ERROR                 assert prints an error and ARB exits
50 * ASSERT_PRINT                 assert prints a message (anyway) and ARB continues
51 * ASSERT_NONE                  assertions inactive
52 *
53 * ------------------------------------------------------------ */
54
55// check correct definition of DEBUG/NDEBUG
56#ifndef NDEBUG
57# ifndef DEBUG
58#  error Neither DEBUG nor NDEBUG is defined!
59# endif
60#else
61# ifdef DEBUG
62#  error Both DEBUG and NDEBUG are defined - only one should be!
63# endif
64#endif
65
66#ifdef arb_assert
67#error arb_assert already defined
68#endif
69
70// --------------------------------------------------------------------
71// use exactly ONE of the following ASSERT_xxx defines in each section:
72#if defined(DEBUG) && !defined(DEVEL_RELEASE)
73
74// assert that raises SIGSEGV (recommended for DEBUG version!)
75// # define ASSERT_CRASH
76// # define ASSERT_BACKTRACE_AND_CRASH
77// # define ASSERT_STOP
78# define ASSERT_BACKTRACE_AND_STOP
79// test if a bug has to do with assertion code
80// # define ASSERT_NONE
81
82#else
83
84// no assert (recommended for final version!)
85# define ASSERT_NONE
86// assert as error in final version (allows basic debugging of NDEBUG version)
87// # define ASSERT_ERROR
88// assert as print in final version (allows basic debugging of NDEBUG version)
89// # define ASSERT_PRINT
90
91#endif
92
93// ------------------------------------------------------------
94
95#if defined(__cplusplus)
96inline void provoke_core_dump() {
97    raise(SIGSEGV);
98}
99#else // !defined(__cplusplus)
100#define provoke_core_dump() do { *(int*)0 = 0; } while(0)
101#endif
102
103// ------------------------------------------------------------
104
105#if defined(SIMPLE_ARB_ASSERT)
106
107// code here is independent from CORE library and glib
108
109#define ARB_SIGSEGV(backtrace) do {     \
110        provoke_core_dump();            \
111    } while (0)
112
113#define ARB_STOP(backtrace) ARB_SIGSEGV(backtrace)
114
115#ifndef ASSERT_NONE
116# define arb_assert(cond)                                               \
117    do {                                                                \
118        if (!(cond)) {                                                  \
119            fprintf(stderr, "Assertion '%s' failed in '%s' #%i\n",      \
120                    #cond, __FILE__, __LINE__);                         \
121            provoke_core_dump();                                        \
122        }                                                               \
123    } while (0)
124#endif
125
126
127// ------------------------------------------------------------
128
129#else // !SIMPLE_ARB_ASSERT
130
131/* Provoke a SIGSEGV (which will stop the debugger or terminated the application)
132 * Do backtrace manually here and uninstall SIGSEGV-handler
133 * (done because automatic backtrace on SIGSEGV lacks name of current function)
134 */
135
136#ifndef ARB_CORE_H
137#include <arb_core.h>
138#endif
139
140#if (GCC_VERSION_CODE>=407) && (GCC_VERSION_CODE<600)
141// unfixable warnings in glib headers for gcc 4.7.x .. 5.5.0
142# pragma GCC diagnostic push
143# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
144#endif
145
146#ifndef __G_LIB_H__
147#include <glib.h>
148#endif
149
150#if (GCC_VERSION_CODE>=407) && (GCC_VERSION_CODE<600)
151# pragma GCC diagnostic pop
152#endif
153
154#define stop_in_debugger() G_BREAKPOINT()
155
156// the purpose of TRIGGER_SANITIZER is simply to provide a traceback
157// leading to the location of the assert(or similar) which triggered
158// this function.
159//
160// With older gcc versions provoke_core_dump() itself caused AddressSanitizer
161// to dump the stack to the compile log (in error-message format).
162//
163// Now we need to do something illegal in such a complicated way,
164// that the compiler is not able to detect that it is illegal.
165// -> sanitizer will trigger
166
167#if defined(LEAKS_SANITIZED)
168# define TRIGGER_SANITIZER() delete ((char*)GBK_getNonfreeableAddress())
169#else // !LEAKS_SANITIZED
170# define TRIGGER_SANITIZER()
171#endif
172
173
174#define ARB_SIGSEGV(backtrace) do {                             \
175        if (backtrace) GBK_dump_backtrace(NULp, "ARB_SIGSEGV"); \
176        GBK_install_SIGSEGV_handler(false);                     \
177        TRIGGER_SANITIZER();                                    \
178        provoke_core_dump();                                    \
179    } while (0)
180
181#define ARB_STOP(backtrace)                                     \
182    do {                                                        \
183        if (backtrace) GBK_dump_backtrace(NULp, "ARB_STOP");    \
184        stop_in_debugger();                                     \
185    } while(0)
186
187# define arb_assert_crash(cond)         \
188    do {                                \
189        if (!(cond)) ARB_SIGSEGV(0);    \
190    } while (0)
191
192# define arb_assert_stop(cond)          \
193    do {                                \
194        if (!(cond)) ARB_STOP(0);       \
195    } while (0)
196
197# define arb_assert_backtrace_and_crash(cond)                           \
198    do {                                                                \
199        if (!(cond)) {                                                  \
200            fputs(GBK_assert_msg(#cond, __FILE__, __LINE__), stderr);   \
201            fflush(stderr);                                             \
202            ARB_SIGSEGV(1);                                             \
203        }                                                               \
204    } while (0)
205
206# define arb_assert_backtrace_and_stop(cond)                            \
207    do {                                                                \
208        if (!(cond)) {                                                  \
209            fputs(GBK_assert_msg(#cond, __FILE__, __LINE__), stderr);   \
210            fflush(stderr);                                             \
211            ARB_STOP(1);                                                \
212        }                                                               \
213    } while (0)
214
215#ifdef ASSERT_CRASH
216# define arb_assert(cond) arb_assert_crash(cond)
217#endif
218#ifdef ASSERT_STOP
219# define arb_assert(cond) arb_assert_stop(cond)
220#endif
221#ifdef ASSERT_BACKTRACE_AND_CRASH
222# define arb_assert(cond) arb_assert_backtrace_and_crash(cond)
223#endif
224#ifdef ASSERT_BACKTRACE_AND_STOP
225# define arb_assert(cond) arb_assert_backtrace_and_stop(cond)
226#endif
227#ifdef ASSERT_ERROR
228# define arb_assert(cond) assert_or_exit(cond)
229#endif
230
231#ifdef ASSERT_PRINT
232# define arb_assert(cond)                                               \
233    do {                                                                \
234        fprintf(stderr, "at %s #%i\n", __FILE__, __LINE__);             \
235        if (!(cond)) fprintf(stderr, "assertion '%s' failed!\n", #cond); \
236        fflush(stderr);                                                 \
237    } while (0)
238#endif
239
240#endif // SIMPLE_ARB_ASSERT
241
242// ------------------------------------------------------------
243
244#ifdef ASSERT_NONE
245# define arb_assert(cond)
246#else
247# define ASSERTION_USED
248#endif
249
250#undef ASSERT_CRASH
251#undef ASSERT_BACKTRACE_AND_CRASH
252#undef ASSERT_STOP
253#undef ASSERT_BACKTRACE_AND_STOP
254#undef ASSERT_ERROR
255#undef ASSERT_PRINT
256#undef ASSERT_NONE
257
258#ifndef arb_assert
259# error arb_assert has not been defined -- check ASSERT_xxx definitions
260#endif
261
262#if !defined(SIMPLE_ARB_ASSERT)
263#define assert_or_exit(cond)                                            \
264    do {                                                                \
265        if (!(cond)) {                                                  \
266            GBK_terminate(GBK_assert_msg(#cond, __FILE__, __LINE__));   \
267        }                                                               \
268    } while (0)
269#endif // SIMPLE_ARB_ASSERT
270
271// ------------------------------------------------------------
272
273#ifdef UNIT_TESTS // UT_DIFF
274#ifndef TEST_GLOBAL_H
275#include <test_global.h> // overrides arb_assert()!
276#endif
277#else
278#define RUNNING_TEST() false
279#endif
280
281#ifndef CXXFORWARD_H
282#include <cxxforward.h>
283#endif
284
285// ------------------------------------------------------------
286// logical operators (mostly used for assertions)
287
288// Note: 'conclusion' is not evaluated if 'hypothesis' is wrong!
289#define implicated(hypothesis,conclusion) (!(hypothesis) || !!(conclusion))
290
291#ifdef __cplusplus
292CONSTEXPR_INLINE bool correlated(bool hypo1, bool hypo2) { return implicated(hypo1, hypo2) == implicated(hypo2, hypo1); } // equivalence!
293CONSTEXPR_INLINE bool contradicted(bool hypo1, bool hypo2) { return !correlated(hypo1, hypo2); } // non-equivalence!
294#endif
295
296// ------------------------------------------------------------
297// use the following macros for parameters etc. only appearing in one version
298
299#ifdef DEBUG
300# define IF_DEBUG(x) x
301# define IF_NDEBUG(x)
302#else
303# define IF_DEBUG(x)
304# define IF_NDEBUG(x) x
305#endif
306
307#ifdef ASSERTION_USED
308# define IF_ASSERTION_USED(x) x
309#else
310# define IF_ASSERTION_USED(x)
311#endif
312
313// ------------------------------------------------------------
314// assertion tolerant constexpr modifiers
315
316#if defined(ASSERTION_USED)
317# define ASSERTING_CONSTEXPR_INLINE       inline
318# define ASSERTING_CONSTEXPR_INLINE_Cxx14 inline
319#else // !ASSERTION_USED
320# define ASSERTING_CONSTEXPR_INLINE       CONSTEXPR_INLINE
321# define ASSERTING_CONSTEXPR_INLINE_Cxx14 CONSTEXPR_INLINE_Cxx14
322#endif
323
324// ------------------------------------------------------------
325// Assert specific result in DEBUG and silence __ATTR__USERESULT warnings in NDEBUG.
326//
327// The value 'Expected' (or 'Limit') should be side-effect-free (it is only executed in DEBUG mode).
328// The given 'Expr' is evaluated under all conditions!
329//
330// Important note:
331//      When you swap 'Expected' and 'Expr' by mistake,
332//      code working in DEBUG, may suddenly stop working in NDEBUG!
333
334#ifdef ASSERTION_USED
335
336# define ASSERT_RESULT(Type, Expected, Expr) do {       \
337        Type value = (Expr);                            \
338        arb_assert(value == (Expected));                \
339    } while (0)
340
341# define ASSERT_RESULT_PREDICATE(Pred, Expr) do {       \
342        arb_assert(Pred(Expr));                         \
343    } while (0)
344
345#else
346
347template <typename T> inline void dont_warn_unused_result(T) {}
348
349# define ASSERT_RESULT(Type, Expected, Expr) do {       \
350        dont_warn_unused_result<Type>(Expr);            \
351    } while(0)
352
353# define ASSERT_RESULT_PREDICATE(Pred, Expr) do {       \
354        (void)Expr;                                     \
355    } while(0)
356
357#endif
358
359#define ASSERT_NULL_RESULT(ptrExpr) ASSERT_RESULT(const void*, NULp, ptrExpr)
360#define ASSERT_NO_ERROR(errorExpr)  ASSERT_RESULT(GB_ERROR, NULp, errorExpr)
361
362#define ASSERT_TRUE(boolExpr)  ASSERT_RESULT(bool, true, boolExpr)
363#define ASSERT_FALSE(boolExpr) ASSERT_RESULT(bool, false, boolExpr)
364
365// ------------------------------------------------------------
366
367#if defined(ASSERTION_USED)
368inline bool knownNonNull(const void *nonnull) { // use to suppress -Wnonnull-compare (only allowed in assertions)
369    return nonnull;
370}
371#endif
372
373// ------------------------------------------------------------
374// UNCOVERED is used to
375// - check for existing and
376// - document missing test coverage.
377// See ../INCLUDE/test_global.h@UNCOVERED
378
379#ifndef UNCOVERED
380#define UNCOVERED()
381#endif
382
383// ------------------------------------------------------------
384
385#ifdef DEVEL_RELEASE
386# ifdef ASSERTION_USED
387#  error Assertions enabled in release
388# endif
389#endif
390
391// ------------------------------------------------------------
392
393#if !defined(SIMPLE_ARB_ASSERT)
394#ifndef ARB_CORE_H
395#include <arb_core.h>
396#endif
397#endif // SIMPLE_ARB_ASSERT
398
399#else
400#error arb_assert.h included twice
401#endif // ARB_ASSERT_H
402
Note: See TracBrowser for help on using the repository browser.