void fr_fault_set_cb(fr_fault_cb_t func);
void fr_fault_set_log_fd(int fd);
void fr_fault_log(char const *msg, ...) CC_HINT(format (printf, 1, 2));
-bool fr_cond_assert_fail(char const *file, int line, char const *expr);
+bool fr_cond_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
+ CC_HINT(format (printf, 4, 5));
/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
*
*
* @param _x expression to test (should evaluate to true)
*/
-#define fr_cond_assert(_x) likely((bool)((_x) ? true : (fr_cond_assert_fail(__FILE__, __LINE__, #_x) && false)))
+#define fr_cond_assert(_x) likely((bool)((_x) ? true : (fr_cond_assert_fail(__FILE__, __LINE__, #_x, NULL) && false)))
+
+/** Calls panic_action ifndef NDEBUG, else logs error and evaluates to value of _x
+ *
+ * Should be wrapped in a condition, and if false, should cause function to return
+ * an error code. This allows control to return to the caller if a precondition is
+ * not satisfied and we're not debugging.
+ *
+ * Example:
+ @verbatim
+ if (!fr_cond_assert_msg(request, "Bad stuff happened: %s", fr_syserror(errno)))) return -1
+ @endverbatim
+ *
+ * @param _x expression to test (should evaluate to true)
+ * @param _fmt of message to log.
+ * @param ... fmt arguments.
+ */
+#define fr_cond_assert_msg(_x, _fmt, ...) likely((bool)((_x) ? true : (fr_cond_assert_fail(__FILE__, __LINE__, #_x, _fmt, ## __VA_ARGS__) && false)))
void NEVER_RETURNS _fr_exit(char const *file, int line, int status);
# define fr_exit(_x) _fr_exit(__FILE__, __LINE__, (_x))
/** A soft assertion which triggers the fault handler in debug builds
*
- * @param file the assertion failed in.
- * @param line of the assertion in the file.
- * @param expr that was evaluated.
+ * @param[in] file the assertion failed in.
+ * @param[in] line of the assertion in the file.
+ * @param[in] expr that was evaluated.
+ * @param[in] fmt Message to print (may be NULL).
+ * @param[in] ... Arguments for msg string.
* @return the value of cond.
*/
-bool fr_cond_assert_fail(char const *file, int line, char const *expr)
+bool fr_cond_assert_fail(char const *file, int line, char const *expr, char const *msg, ...)
{
+ if (msg) {
+ char str[256]; /* Decent compilers won't allocate this unless fmt is !NULL... */
+ va_list ap;
+
+ va_start(ap, msg);
+ (void)vsnprintf(str, sizeof(str), msg, ap);
+ va_end(ap);
+
+#ifndef NDEBUG
+ FR_FAULT_LOG("ASSERT FAILED %s[%u]: %s: %s", file, line, expr, str);
+ fr_fault(SIGABRT);
+#else
+ FR_FAULT_LOG("ASSERT WOULD FAIL %s[%u]: %s: %s", file, line, expr, str);
+#endif
+ }
+
#ifndef NDEBUG
FR_FAULT_LOG("ASSERT FAILED %s[%u]: %s", file, line, expr);
fr_fault(SIGABRT);
* If this fails, assert on debug builds, but ignore it at run-time.
*/
if (kevent(el->kq, evset, count, NULL, 0, NULL) < 0) {
- (void) fr_cond_assert("FD was closed without being removed from the KQ" == NULL);
+ (void) fr_cond_assert_msg(false, "FD was closed without being removed from the KQ: %s",
+ fr_syserror(errno));
}
}