mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 10:07:04 +00:00 
			
		
		
		
	The previous method, using zassert.h and hoping nothing includes assert.h (which, on glibc at least, just does "#undef assert" and puts its own definition in...) was fragile - and actually broke undetected. Just provide our own assert.h and control overriding by putting it in a separate directory to add to the include path (or not.) Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
		
			
				
	
	
		
			99 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2021  David Lamparter, for NetDEF, Inc.
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, and distribute this software for any
 | 
						|
 * purpose with or without fee is hereby granted, provided that the above
 | 
						|
 * copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
						|
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 */
 | 
						|
 | 
						|
/* WARNING: this file is "special" in that it overrides the system-provided
 | 
						|
 * assert.h by being on the include path before it.  That means it should
 | 
						|
 * provide the functional equivalent.
 | 
						|
 *
 | 
						|
 * This is intentional because FRR extends assert() to write to the log and
 | 
						|
 * add backtraces.  Overriding the entire file is the simplest and most
 | 
						|
 * reliable way to get this to work;  there were problems previously with the
 | 
						|
 * system assert.h getting included afterwards and redefining assert() back to
 | 
						|
 * the system variant.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef _FRR_ASSERT_H
 | 
						|
#define _FRR_ASSERT_H
 | 
						|
 | 
						|
#include "xref.h"
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C" {
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef __cplusplus
 | 
						|
/* C++ has this built-in, but C provides it in assert.h for >=C11.  Since we
 | 
						|
 * replace assert.h entirely, we need to provide it here too.
 | 
						|
 */
 | 
						|
#define static_assert _Static_assert
 | 
						|
#endif
 | 
						|
 | 
						|
struct xref_assert {
 | 
						|
	struct xref xref;
 | 
						|
 | 
						|
	const char *expr;
 | 
						|
	const char *extra, *args;
 | 
						|
};
 | 
						|
 | 
						|
extern void _zlog_assert_failed(const struct xref_assert *xref,
 | 
						|
				const char *extra, ...) PRINTFRR(2, 3)
 | 
						|
	__attribute__((noreturn));
 | 
						|
 | 
						|
/* the "do { } while (expr_)" is there to get a warning for assignments inside
 | 
						|
 * the assert expression aka "assert(x = 1)".  The (necessary) braces around
 | 
						|
 * expr_ in the if () statement would suppress these warnings.  Since
 | 
						|
 * _zlog_assert_failed() is noreturn, the while condition will never be
 | 
						|
 * checked.
 | 
						|
 */
 | 
						|
#define assert(expr_)                                                          \
 | 
						|
	({                                                                     \
 | 
						|
		static const struct xref_assert _xref __attribute__(           \
 | 
						|
			(used)) = {                                            \
 | 
						|
			.xref = XREF_INIT(XREFT_ASSERT, NULL, __func__),       \
 | 
						|
			.expr = #expr_,                                        \
 | 
						|
		};                                                             \
 | 
						|
		XREF_LINK(_xref.xref);                                         \
 | 
						|
		if (__builtin_expect((expr_) ? 0 : 1, 0))                      \
 | 
						|
			do {                                                   \
 | 
						|
				_zlog_assert_failed(&_xref, NULL);             \
 | 
						|
			} while (expr_);                                       \
 | 
						|
	})
 | 
						|
 | 
						|
#define assertf(expr_, extra_, ...)                                            \
 | 
						|
	({                                                                     \
 | 
						|
		static const struct xref_assert _xref __attribute__(           \
 | 
						|
			(used)) = {                                            \
 | 
						|
			.xref = XREF_INIT(XREFT_ASSERT, NULL, __func__),       \
 | 
						|
			.expr = #expr_,                                        \
 | 
						|
			.extra = extra_,                                       \
 | 
						|
			.args = #__VA_ARGS__,                                  \
 | 
						|
		};                                                             \
 | 
						|
		XREF_LINK(_xref.xref);                                         \
 | 
						|
		if (__builtin_expect((expr_) ? 0 : 1, 0))                      \
 | 
						|
			do {                                                   \
 | 
						|
				_zlog_assert_failed(&_xref, extra_,            \
 | 
						|
						    ##__VA_ARGS__);            \
 | 
						|
			} while (expr_);                                       \
 | 
						|
	})
 | 
						|
 | 
						|
#define zassert assert
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#endif /* _FRR_ASSERT_H */
 |