2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @brief Various functions to aid in debugging
21 * @copyright 2013 The FreeRADIUS server project
22 * @copyright 2013 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
25 #include <freeradius-devel/libradius.h>
29 #if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
34 * runtime backtrace functions are not POSIX but are included in
35 * glibc, OSX >= 10.5 and various BSDs
38 # include <execinfo.h>
41 #ifdef HAVE_SYS_PRCTL_H
42 # include <sys/prctl.h>
45 #ifdef HAVE_SYS_PTRACE_H
46 # include <sys/ptrace.h>
47 # if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
48 # define PTRACE_ATTACH PT_ATTACH
50 # if !defined(PTRACE_CONT) && defined(PT_CONTINUE)
51 # define PTRACE_CONT PT_CONTINUE
53 # if !defined(PTRACE_DETACH) && defined(PT_DETACH)
54 # define PTRACE_DETACH PT_DETACH
58 #ifdef HAVE_SYS_RESOURCE_H
59 # include <sys/resource.h>
63 # define PTHREAD_MUTEX_LOCK pthread_mutex_lock
64 # define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
66 # define PTHREAD_MUTEX_LOCK(_x)
67 # define PTHREAD_MUTEX_UNLOCK(_x)
71 # ifndef MAX_BT_FRAMES
72 # define MAX_BT_FRAMES 128
75 # define MAX_BT_CBUFF 1048576 //!< Should be a power of 2
78 # ifdef HAVE_PTHREAD_H
79 static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
82 typedef struct fr_bt_info {
83 void *obj; //!< Memory address of the block of allocated memory.
84 void *frames[MAX_BT_FRAMES]; //!< Backtrace frame data
85 int count; //!< Number of frames stored
89 void *obj; //!< Pointer to the parent object, this is our needle
90 //!< when we iterate over the contents of the circular buffer.
91 fr_cbuff_t *cbuff; //!< Where we temporarily store the backtraces
95 static char panic_action[512]; //!< The command to execute when panicking.
96 static fr_fault_cb_t panic_cb = NULL; //!< Callback to execute whilst panicking, before the
99 static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...);
101 static fr_fault_log_t fr_fault_log = _fr_fault_log; //!< Function to use to process logging output.
102 static int fr_fault_log_fd = STDERR_FILENO; //!< Where to write debug output.
104 static int debugger_attached = -1; //!< Whether were attached to by a debugger.
106 #ifdef HAVE_SYS_RESOURCE_H
107 static struct rlimit core_limits;
110 static TALLOC_CTX *talloc_null_ctx;
111 static TALLOC_CTX *talloc_autofree_ctx;
113 #define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
115 #ifdef HAVE_SYS_PTRACE_H
117 # define _PTRACE(_x, _y) ptrace(_x, _y, NULL, NULL)
119 # define _PTRACE(_x, _y) ptrace(_x, _y, NULL, 0)
122 /** Determine if we're running under a debugger by attempting to attach using pattach
124 * @return 0 if we're not, 1 if we are, -1 if we can't tell.
126 static int fr_debugger_attached(void)
130 int from_child[2] = {-1, -1};
132 if (pipe(from_child) < 0) {
133 fr_strerror_printf("Debugger check failed: Error opening internal pipe: %s", fr_syserror(errno));
139 fr_strerror_printf("Debugger check failed: Error forking: %s", fr_syserror(errno));
146 int ppid = getppid();
148 /* Close parent's side */
149 close(from_child[0]);
151 if (_PTRACE(PTRACE_ATTACH, ppid) == 0) {
152 /* If we attached then we're not running under a debugger */
153 if (write(from_child[1], &ret, sizeof(ret)) < 0) {
154 fprintf(stderr, "Writing ptrace status to parent failed: %s", fr_syserror(errno));
157 /* Wait for the parent to stop and continue it */
158 waitpid(ppid, NULL, 0);
159 _PTRACE(PTRACE_CONT, ppid);
162 _PTRACE(PTRACE_DETACH, ppid);
167 /* Something is already attached */
168 if (write(from_child[1], &ret, sizeof(ret)) < 0) {
169 fprintf(stderr, "Writing ptrace status to parent failed: %s", fr_syserror(errno));
178 * The child writes a 1 if pattach failed else 0.
180 * This read may be interrupted by pattach,
181 * which is why we need the loop.
183 while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
185 /* Ret not updated */
187 fr_strerror_printf("Debugger check failed: Error getting status from child: %s",
191 /* Close the pipes here (if we did it above, it might race with pattach) */
192 close(from_child[1]);
193 close(from_child[0]);
195 /* Collect the status of the child */
196 waitpid(pid, NULL, 0);
202 static int fr_debugger_attached(void)
204 fr_strerror_printf("Debugger check failed: PTRACE not available");
210 /** Break in debugger (if were running under a debugger)
212 * If the server is running under a debugger this will raise a
213 * SIGTRAP which will pause the running process.
215 * If the server is not running under debugger then this will do nothing.
217 void fr_debug_break(void)
219 if (debugger_attached == -1) {
220 debugger_attached = fr_debugger_attached();
223 if (debugger_attached == 1) {
224 fprintf(stderr, "Debugger detected, raising SIGTRAP\n");
232 /** Print backtrace entry for a given object
234 * @param cbuff to search in.
235 * @param obj pointer to original object
237 void backtrace_print(fr_cbuff_t *cbuff, void *obj)
242 while ((p = fr_cbuff_rp_next(cbuff, NULL))) {
243 if ((p->obj == obj) || !obj) {
246 fprintf(stderr, "Stacktrace for: %p\n", p->obj);
247 backtrace_symbols_fd(p->frames, p->count, STDERR_FILENO);
252 fprintf(stderr, "No backtrace available for %p", obj);
256 /** Generate a backtrace for an object
258 * If this is the first entry being inserted
260 int fr_backtrace_do(fr_bt_marker_t *marker)
264 if (!fr_assert(marker->obj) || !fr_assert(marker->cbuff)) return -1;
266 bt = talloc_zero(NULL, fr_bt_info_t);
269 bt->obj = marker->obj;
270 bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
272 fr_cbuff_rp_insert(marker->cbuff, bt);
277 /** Inserts a backtrace marker into the provided context
279 * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
281 * Code augmentation should look something like:
283 // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it
284 static fr_cbuff_t *my_obj_bt;
286 my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
289 this = talloc(ctx, my_obj_t);
291 // Attach backtrace marker to object
292 backtrace_attach(&my_obj_bt, this);
298 * Then, later when a double free occurs:
300 (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
303 * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
304 * values, but should at least show the code path taken.
306 * @param cbuff this should be a pointer to a static *fr_cbuff.
307 * @param obj we want to generate a backtrace for.
309 fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj)
311 fr_bt_marker_t *marker;
313 if (*cbuff == NULL) {
314 PTHREAD_MUTEX_LOCK(&fr_debug_init);
315 /* Check again now we hold the mutex - eww*/
316 if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true);
317 PTHREAD_MUTEX_UNLOCK(&fr_debug_init);
320 marker = talloc(obj, fr_bt_marker_t);
325 marker->obj = (void *) obj;
326 marker->cbuff = *cbuff;
328 fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
330 * Generate the backtrace for memory allocation
332 fr_backtrace_do(marker);
333 talloc_set_destructor(marker, fr_backtrace_do);
338 void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj)
340 fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
342 fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj)
344 fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
347 #endif /* ifdef HAVE_EXECINFO */
349 static int _panic_on_free(UNUSED char *foo)
352 return -1; /* this should make the free fail */
355 /** Insert memory into the context of another talloc memory chunk which
356 * causes a panic when freed.
358 * @param ctx TALLOC_CTX to monitor for frees.
360 void fr_panic_on_free(TALLOC_CTX *ctx)
364 ptr = talloc(ctx, char);
365 talloc_set_destructor(ptr, _panic_on_free);
368 /** Set the dumpable flag, also controls whether processes can PATTACH
370 * @param dumpable whether we should allow core dumping
372 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
373 static int fr_set_dumpable_flag(bool dumpable)
375 if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
376 fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
384 static int fr_set_dumpable_flag(UNUSED bool dumpable)
386 fr_strerror_printf("Changing value of PR_DUMPABLE not supported on this system");
391 /** Get the processes dumpable flag
394 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE)
395 static int fr_get_dumpable_flag(void)
399 ret = prctl(PR_GET_DUMPABLE);
401 fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
406 * Linux is crazy and prctl sometimes returns 2 for disabled
408 if (ret != 1) return 0;
412 static int fr_get_dumpable_flag(void)
414 fr_strerror_printf("Getting value of PR_DUMPABLE not supported on this system");
420 /** Get the current maximum for core files
422 * Do this before anything else so as to ensure it's properly initialized.
424 int fr_set_dumpable_init(void)
426 #ifdef HAVE_SYS_RESOURCE_H
427 if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
428 fr_strerror_printf("Failed to get current core limit: %s", fr_syserror(errno));
435 /** Enable or disable core dumps
437 * @param allow_core_dumps whether to enable or disable core dumps.
439 int fr_set_dumpable(bool allow_core_dumps)
442 * If configured, turn core dumps off.
444 if (!allow_core_dumps) {
445 #ifdef HAVE_SYS_RESOURCE_H
446 struct rlimit no_core;
448 no_core.rlim_cur = 0;
449 no_core.rlim_max = 0;
451 if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
452 fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
460 if (fr_set_dumpable_flag(true) < 0) return -1;
463 * Reset the core dump limits to their original value.
465 #ifdef HAVE_SYS_RESOURCE_H
466 if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
467 fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
475 /** Check to see if panic_action file is world writeable
477 * @return 0 if file is OK, else -1.
479 static int fr_fault_check_permissions(void)
487 * Try and guess which part of the command is the binary, and check to see if
488 * it's world writeable, to try and save the admin from their own stupidity.
490 * @fixme we should do this properly and take into account single and double
493 if ((q = strchr(panic_action, ' '))) {
495 * need to use a static buffer, because mallocing memory in a signal handler
496 * is a bad idea and can result in deadlock.
498 len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
499 if (is_truncated(len, sizeof(filename))) {
500 fr_strerror_printf("Failed writing panic_action to temporary buffer (truncated)");
508 if (stat(p, &statbuf) == 0) {
510 if ((statbuf.st_mode & S_IWOTH) != 0) {
511 fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
520 /** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
524 void fr_fault(int sig)
526 char cmd[sizeof(panic_action) + 20];
528 size_t left = sizeof(cmd), ret;
530 char const *p = panic_action;
536 * Makes the backtraces slightly cleaner
538 memset(cmd, 0, sizeof(cmd));
540 FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
543 * Check for administrator sanity.
545 if (fr_fault_check_permissions() < 0) {
546 FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
551 * Run the callback if one was registered
553 if (panic_cb && (panic_cb(sig) < 0)) goto finish;
556 * Produce a simple backtrace - They've very basic but at least give us an
557 * idea of the area of the code we hit the issue in.
559 * See below in fr_fault_setup() and
560 * https://sourceware.org/bugzilla/show_bug.cgi?id=16159
561 * for why we only print backtraces in debug builds if we're using GLIBC.
563 #if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
565 size_t frame_count, i;
566 void *stack[MAX_BT_FRAMES];
569 frame_count = backtrace(stack, MAX_BT_FRAMES);
571 FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
574 * Only use backtrace_symbols() if we don't have a logging fd.
575 * If the server has experienced memory corruption, there's
576 * a high probability that calling backtrace_symbols() which
577 * mallocs more memory, will fail.
579 if (fr_fault_log_fd < 0) {
580 strings = backtrace_symbols(stack, frame_count);
581 for (i = 0; i < frame_count; i++) {
582 FR_FAULT_LOG("%s", strings[i]);
586 backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
591 /* No panic action set... */
592 if (panic_action[0] == '\0') {
593 FR_FAULT_LOG("No panic action set");
597 /* Substitute %p for the current PID (useful for attaching a debugger) */
598 while ((q = strstr(p, "%p"))) {
599 out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
602 FR_FAULT_LOG("Panic action too long");
608 if (strlen(p) >= left) goto oob;
609 strlcpy(out, p, left);
611 FR_FAULT_LOG("Calling: %s", cmd);
614 bool disable = false;
617 * Here we temporarily enable the dumpable flag so if GBD or LLDB
618 * is called in the panic_action, they can pattach to the running
621 if (fr_get_dumpable_flag() == 0) {
622 if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) {
623 FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
627 FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
633 * We only want to error out here, if dumpable was originally disabled
634 * and we managed to change the value to enabled, but failed
635 * setting it back to disabled.
638 FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
639 if (fr_set_dumpable_flag(false) < 0) {
640 FR_FAULT_LOG("Failed reseting dumpable flag to off: %s", fr_strerror());
641 FR_FAULT_LOG("Exiting due to insecure process state");
647 FR_FAULT_LOG("Panic action exited with %i", code);
651 if (sig == SIGUSR1) {
659 /** Work around debuggers which can't backtrace past the signal handler
661 * At least this provides us some information when we get talloc errors.
663 static void _fr_talloc_fault(char const *reason)
665 fr_fault_log("talloc abort: %s\n", reason);
670 /** Wrapper to pass talloc log output to our fr_fault_log function
673 static void _fr_talloc_log(char const *msg)
675 fr_fault_log("%s\n", msg);
678 /** Generate a talloc memory report for a context and print to stderr/stdout
680 * @param ctx to generate a report for, may be NULL in which case the root context is used.
682 int fr_log_talloc_report(TALLOC_CTX *ctx)
688 fd = dup(fr_fault_log_fd);
690 fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
693 log = fdopen(fd, "w");
696 fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
701 fprintf(log, "Current state of talloced memory:\n");
702 talloc_report_full(talloc_null_ctx, log);
704 fprintf(log, "Talloc chunk lineage:\n");
705 fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx));
706 while ((ctx = talloc_parent(ctx))) fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx));
710 fprintf(log, "Talloc context level %i:\n", i++);
711 talloc_report_full(ctx, log);
712 } while ((ctx = talloc_parent(ctx)) &&
713 (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */
714 (talloc_parent(ctx) != talloc_null_ctx)); /* Stop before we hit NULL ctx */
722 /** Signal handler to print out a talloc memory report
726 static void _fr_fault_mem_report(int sig)
728 FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
730 if (fr_log_talloc_report(NULL) < 0) fr_perror("memreport");
733 static int _fr_disable_null_tracking(UNUSED bool *p)
735 talloc_disable_null_tracking();
739 /** Registers signal handlers to execute panic_action on fatal signal
741 * May be called multiple time to change the panic_action/program.
743 * @param cmd to execute on fault. If present %p will be substituted
744 * for the parent PID before the command is executed, and %e
745 * will be substituted for the currently running program.
746 * @param program Name of program currently executing (argv[0]).
747 * @return 0 on success -1 on failure.
749 int fr_fault_setup(char const *cmd, char const *program)
751 static bool setup = false;
753 char *out = panic_action;
754 size_t left = sizeof(panic_action), ret;
760 /* Substitute %e for the current program */
761 while ((q = strstr(p, "%e"))) {
762 out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
765 fr_strerror_printf("Panic action too long");
771 if (strlen(p) >= left) goto oob;
772 strlcpy(out, p, left);
774 *panic_action = '\0';
778 * Check for administrator sanity.
780 if (fr_fault_check_permissions() < 0) return -1;
782 /* Unsure what the side effects of changing the signal handler mid execution might be */
784 debugger_attached = fr_debugger_attached();
787 * These signals can't be properly dealt with in the debugger
788 * if we set our own signal handlers
790 if (debugger_attached == 0) {
792 if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
795 if (fr_set_signal(SIGBUS, fr_fault) < 0) return -1;
798 if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
802 if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
805 * Use this instead of abort so we get a
806 * full backtrace with broken versions of LLDB
808 talloc_set_abort_fn(_fr_talloc_fault);
812 if (fr_set_signal(SIGUSR1, fr_fault) < 0) return -1;
816 if (fr_set_signal(SIGUSR2, _fr_fault_mem_report) < 0) return -1;
820 * Setup the default logger
822 if (!fr_fault_log) fr_fault_set_log_fn(NULL);
823 talloc_set_log_fn(_fr_talloc_log);
826 * Needed for memory reports
832 tmp = talloc(NULL, bool);
833 talloc_null_ctx = talloc_parent(tmp);
837 * Disable null tracking on exit, else valgrind complains
839 talloc_autofree_ctx = talloc_autofree_context();
840 marker = talloc(talloc_autofree_ctx, bool);
841 talloc_set_destructor(marker, _fr_disable_null_tracking);
844 #if defined(HAVE_MALLOPT) && !defined(NDEBUG)
846 * If were using glibc malloc > 2.4 this scribbles over
847 * uninitialised and freed memory, to make memory issues easier
850 if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42);
851 mallopt(M_CHECK_ACTION, 3);
854 #if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
856 * We need to pre-load lgcc_s, else we can get into a deadlock
857 * in fr_fault, as backtrace() attempts to dlopen it.
859 * Apparently there's a performance impact of loading lgcc_s,
860 * so only do it if this is a debug build.
862 * See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159
867 backtrace(stack, 10);
876 /** Set a callback to be called before fr_fault()
878 * @param func to execute. If callback returns < 0
879 * fr_fault will exit before running panic_action code.
881 void fr_fault_set_cb(fr_fault_cb_t func)
886 /** Default logger, logs output to stderr
889 static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...)
894 vfprintf(stderr, msg, ap);
898 /** Set a file descriptor to log panic_action output to.
900 * @param func to call to output log messages.
902 void fr_fault_set_log_fn(fr_fault_log_t func)
904 fr_fault_log = func ? func : _fr_fault_log;
907 /** Set a file descriptor to log memory reports to.
909 * @param fd to write output to.
911 void fr_fault_set_log_fd(int fd)
913 fr_fault_log_fd = fd;
916 #ifdef WITH_VERIFY_PTR
919 * Verify a VALUE_PAIR
921 inline void fr_verify_vp(char const *file, int line, VALUE_PAIR const *vp)
924 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR pointer was NULL", file, line);
929 (void) talloc_get_type_abort(vp, VALUE_PAIR);
931 if (vp->data.ptr) switch (vp->da->type) {
938 if (!talloc_get_type(vp->data.ptr, uint8_t)) {
939 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
940 "uint8_t but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
941 (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
944 len = talloc_array_length(vp->vp_octets);
945 if (vp->length > len) {
946 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
947 "uint8_t data buffer length %zu\n", file, line, vp->da->name, vp->length, len);
952 parent = talloc_parent(vp->data.ptr);
954 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
955 "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
956 file, line, vp->da->name,
957 vp, parent, parent ? talloc_get_name(parent) : "NULL");
969 if (!talloc_get_type(vp->data.ptr, char)) {
970 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
971 "char but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
972 (void) talloc_get_type_abort(vp->data.ptr, char);
975 len = (talloc_array_length(vp->vp_strvalue) - 1);
976 if (vp->length > len) {
977 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
978 "char buffer length %zu\n", file, line, vp->da->name, vp->length, len);
983 if (vp->vp_strvalue[vp->length] != '\0') {
984 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer not \\0 "
985 "terminated\n", file, line, vp->da->name);
990 parent = talloc_parent(vp->data.ptr);
992 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" uint8_t buffer is not "
993 "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
994 file, line, vp->da->name,
995 vp, parent, parent ? talloc_get_name(parent) : "NULL");
1008 * Verify a pair list
1010 void fr_verify_list(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps)
1016 for (vp = fr_cursor_init(&cursor, &vps);
1018 vp = fr_cursor_next(&cursor)) {
1021 parent = talloc_parent(vp);
1022 if (expected && (parent != expected)) {
1023 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Expected VALUE_PAIR \"%s\" to be parented "
1024 "by %p (%s), instead parented by %p (%s)\n",
1025 file, line, vp->da->name,
1026 expected, talloc_get_name(expected),
1027 parent, parent ? talloc_get_name(parent) : "NULL");
1029 fr_log_talloc_report(expected);
1030 if (parent) fr_log_talloc_report(parent);
1039 bool fr_assert_cond(char const *file, int line, char const *expr, bool cond)
1042 FR_FAULT_LOG("SOFT ASSERT FAILED %s[%u]: %s", file, line, expr);
1043 #if !defined(NDEBUG) && defined(SIGUSR1)
1052 /** Exit possibly printing a message about why we're exiting.
1054 * Use the fr_exit(status) macro instead of calling this function
1057 * @param file where fr_exit() was called.
1058 * @param line where fr_exit() was called.
1059 * @param status we're exiting with.
1061 void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
1064 char const *error = fr_strerror();
1066 if (error && (status != 0)) {
1067 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
1069 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]", status, file, line);
1072 fr_debug_break(); /* If running under GDB we'll break here */
1077 /** Exit possibly printing a message about why we're exiting.
1079 * Use the fr_exit_now(status) macro instead of calling this function
1082 * @param file where fr_exit_now() was called.
1083 * @param line where fr_exit_now() was called.
1084 * @param status we're exiting with.
1086 void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status)
1089 char const *error = fr_strerror();
1091 if (error && (status != 0)) {
1092 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]. Last error was: %s", status, file, line, error);
1094 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]", status, file, line);
1097 fr_debug_break(); /* If running under GDB we'll break here */