Only register signal handlers if we have a PANIC_ACTION set
[freeradius.git] / src / lib / debug.c
1 /*
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.
6  *
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.
11  *
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
15  */
16
17 /**
18  * @file debug.c
19  * @brief Various functions to aid in debugging
20  *
21  * @copyright 2013  The FreeRADIUS server project
22  * @copyright 2013  Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  */
24 #include <assert.h>
25 #include <freeradius-devel/libradius.h>
26 #include <sys/stat.h>
27
28 #if defined(HAVE_MALLOPT) && defined(HAVE_MALLOC_H)
29 #  include <malloc.h>
30 #endif
31
32 /*
33  *      runtime backtrace functions are not POSIX but are included in
34  *      glibc, OSX >= 10.5 and various BSDs
35  */
36 #ifdef HAVE_EXECINFO
37 #  include <execinfo.h>
38 #endif
39
40 #ifdef HAVE_SYS_PRCTL_H
41 #  include <sys/prctl.h>
42 #endif
43
44 #ifdef HAVE_SYS_RESOURCE_H
45 #  include <sys/resource.h>
46 #endif
47
48 #ifdef HAVE_PTHREAD_H
49 #  define PTHREAD_MUTEX_LOCK pthread_mutex_lock
50 #  define PTHREAD_MUTEX_UNLOCK pthread_mutex_unlock
51 #else
52 #  define PTHREAD_MUTEX_LOCK(_x)
53 #  define PTHREAD_MUTEX_UNLOCK(_x)
54 #endif
55
56 #ifdef HAVE_EXECINFO
57 #  ifndef MAX_BT_FRAMES
58 #    define MAX_BT_FRAMES 128
59 #  endif
60 #  ifndef MAX_BT_CBUFF
61 #    define MAX_BT_CBUFF  1048576                       //!< Should be a power of 2
62 #  endif
63
64 #  ifdef HAVE_PTHREAD_H
65 static pthread_mutex_t fr_debug_init = PTHREAD_MUTEX_INITIALIZER;
66 #  endif
67
68 typedef struct fr_bt_info {
69         void            *obj;                           //!< Memory address of the block of allocated memory.
70         void            *frames[MAX_BT_FRAMES];         //!< Backtrace frame data
71         int             count;                          //!< Number of frames stored
72 } fr_bt_info_t;
73
74 struct fr_bt_marker {
75         void            *obj;                           //!< Pointer to the parent object, this is our needle
76                                                         //!< when we iterate over the contents of the circular buffer.
77         fr_cbuff_t      *cbuff;                         //!< Where we temporarily store the backtraces
78 };
79 #endif
80
81 static char panic_action[512];                          //!< The command to execute when panicking.
82 static fr_fault_cb_t panic_cb = NULL;                   //!< Callback to execute whilst panicking, before the
83                                                         //!< panic_action.
84 static fr_fault_log_t fr_fault_log = NULL;              //!< Function to use to process logging output.
85 static int fr_fault_log_fd = STDERR_FILENO;             //!< Where to write debug output.
86
87 static int fr_debugger_present = -1;                    //!< Whether were attached to by a debugger.
88
89 #ifdef HAVE_SYS_RESOURCE_H
90 static struct rlimit core_limits;
91 #endif
92
93 static TALLOC_CTX *talloc_null_ctx;
94 static TALLOC_CTX *talloc_autofree_ctx;
95
96 #define FR_FAULT_LOG(fmt, ...) fr_fault_log(fmt "\n", ## __VA_ARGS__)
97
98 /** Stub callback to see if the SIGTRAP handler is overriden
99  *
100  * @param signum signal raised.
101  */
102 static void _sigtrap_handler(UNUSED int signum)
103 {
104         fr_debugger_present = 0;
105         signal(SIGTRAP, SIG_DFL);
106 }
107
108 /** Break in debugger (if were running under a debugger)
109  *
110  * If the server is running under a debugger this will raise a
111  * SIGTRAP which will pause the running process.
112  *
113  * If the server is not running under debugger then this will do nothing.
114  */
115 void fr_debug_break(void)
116 {
117         if (fr_debugger_present == -1) {
118                 fr_debugger_present = 0;
119                 signal(SIGTRAP, _sigtrap_handler);
120                 raise(SIGTRAP);
121         } else if (fr_debugger_present == 1) {
122                 raise(SIGTRAP);
123         }
124 }
125
126 #ifdef HAVE_EXECINFO
127 /** Print backtrace entry for a given object
128  *
129  * @param cbuff to search in.
130  * @param obj pointer to original object
131  */
132 void backtrace_print(fr_cbuff_t *cbuff, void *obj)
133 {
134         fr_bt_info_t *p;
135         bool found = false;
136
137         while ((p = fr_cbuff_rp_next(cbuff, NULL))) {
138                 if ((p->obj == obj) || !obj) {
139                         found = true;
140
141                         fprintf(stderr, "Stacktrace for: %p\n", p->obj);
142                         backtrace_symbols_fd(p->frames, p->count, STDERR_FILENO);
143                 }
144         };
145
146         if (!found) {
147                 fprintf(stderr, "No backtrace available for %p", obj);
148         }
149 }
150
151 /** Generate a backtrace for an object
152  *
153  * If this is the first entry being inserted
154  */
155 int fr_backtrace_do(fr_bt_marker_t *marker)
156 {
157         fr_bt_info_t *bt;
158
159         if (!fr_assert(marker->obj) || !fr_assert(marker->cbuff)) return -1;
160
161         bt = talloc_zero(NULL, fr_bt_info_t);
162         if (!bt) return -1;
163
164         bt->obj = marker->obj;
165         bt->count = backtrace(bt->frames, MAX_BT_FRAMES);
166
167         fr_cbuff_rp_insert(marker->cbuff, bt);
168
169         return 0;
170 }
171
172 /** Inserts a backtrace marker into the provided context
173  *
174  * Allows for maximum laziness and will initialise a circular buffer if one has not already been created.
175  *
176  * Code augmentation should look something like:
177 @verbatim
178         // Create a static cbuffer pointer, the first call to backtrace_attach will initialise it
179         static fr_cbuff_t *my_obj_bt;
180
181         my_obj_t *alloc_my_obj(TALLOC_CTX *ctx) {
182                 my_obj_t *this;
183
184                 this = talloc(ctx, my_obj_t);
185
186                 // Attach backtrace marker to object
187                 backtrace_attach(&my_obj_bt, this);
188
189                 return this;
190         }
191 @endverbatim
192  *
193  * Then, later when a double free occurs:
194 @verbatim
195         (gdb) call backtrace_print(&my_obj_bt, <pointer to double freed memory>)
196 @endverbatim
197  *
198  * which should print a limited backtrace to stderr. Note, this backtrace will not include any argument
199  * values, but should at least show the code path taken.
200  *
201  * @param cbuff this should be a pointer to a static *fr_cbuff.
202  * @param obj we want to generate a backtrace for.
203  */
204 fr_bt_marker_t *fr_backtrace_attach(fr_cbuff_t **cbuff, TALLOC_CTX *obj)
205 {
206         fr_bt_marker_t *marker;
207
208         if (*cbuff == NULL) {
209                 PTHREAD_MUTEX_LOCK(&fr_debug_init);
210                 /* Check again now we hold the mutex - eww*/
211                 if (*cbuff == NULL) *cbuff = fr_cbuff_alloc(NULL, MAX_BT_CBUFF, true);
212                 PTHREAD_MUTEX_UNLOCK(&fr_debug_init);
213         }
214
215         marker = talloc(obj, fr_bt_marker_t);
216         if (!marker) {
217                 return NULL;
218         }
219
220         marker->obj = (void *) obj;
221         marker->cbuff = *cbuff;
222
223         fprintf(stderr, "Backtrace attached to %s %p\n", talloc_get_name(obj), obj);
224         /*
225          *      Generate the backtrace for memory allocation
226          */
227         fr_backtrace_do(marker);
228         talloc_set_destructor(marker, fr_backtrace_do);
229
230         return marker;
231 }
232 #else
233 void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj)
234 {
235         fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
236 }
237 fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj)
238 {
239         fprintf(stderr, "Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo\n");
240         abort();
241 }
242 #endif /* ifdef HAVE_EXECINFO */
243
244 static int _panic_on_free(UNUSED char *foo)
245 {
246         fr_fault(SIGUSR1);
247         return -1;      /* this should make the free fail */
248 }
249
250 /** Insert memory into the context of another talloc memory chunk which
251  * causes a panic when freed.
252  *
253  * @param ctx TALLOC_CTX to monitor for frees.
254  */
255 void fr_panic_on_free(TALLOC_CTX *ctx)
256 {
257         char *ptr;
258
259         ptr = talloc(ctx, char);
260         talloc_set_destructor(ptr, _panic_on_free);
261 }
262
263 /** Set the dumpable flag, also controls whether processes can PATTACH
264  *
265  * @param dumpable whether we should allow core dumping
266  */
267 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_SET_DUMPABLE)
268 static int fr_set_dumpable_flag(bool dumpable)
269 {
270         if (prctl(PR_SET_DUMPABLE, dumpable ? 1 : 0) < 0) {
271                 fr_strerror_printf("Cannot re-enable core dumps: prctl(PR_SET_DUMPABLE) failed: %s",
272                                    fr_syserror(errno));
273                 return -1;
274         }
275
276         return 0;
277 }
278 #else
279 static int fr_set_dumpable_flag(UNUSED bool dumpable)
280 {
281         fr_strerror_printf("Changing value of PR_DUMPABLE not supported on this system");
282         return -2;
283 }
284 #endif
285
286 /** Get the processes dumpable flag
287  *
288  */
289 #if defined(HAVE_SYS_PRCTL_H) && defined(PR_GET_DUMPABLE)
290 static int fr_get_dumpable_flag(void)
291 {
292         int ret;
293
294         ret = prctl(PR_GET_DUMPABLE);
295         if (ret < 0) {
296                 fr_strerror_printf("Cannot get dumpable flag: %s", fr_syserror(errno));
297                 return -1;
298         }
299
300         /*
301          *  Linux is crazy and prctl sometimes returns 2 for disabled
302          */
303         if (ret != 1) return 0;
304         return 1;
305 }
306 #else
307 static int fr_get_dumpable_flag(void)
308 {
309         fr_strerror_printf("Getting value of PR_DUMPABLE not supported on this system");
310         return -2;
311 }
312 #endif
313
314
315 /** Get the current maximum for core files
316  *
317  * Do this before anything else so as to ensure it's properly initialized.
318  */
319 int fr_set_dumpable_init(void)
320 {
321 #ifdef HAVE_SYS_RESOURCE_H
322         if (getrlimit(RLIMIT_CORE, &core_limits) < 0) {
323                 fr_strerror_printf("Failed to get current core limit:  %s", fr_syserror(errno));
324                 return -1;
325         }
326 #endif
327         return 0;
328 }
329
330 /** Enable or disable core dumps
331  *
332  * @param allow_core_dumps whether to enable or disable core dumps.
333  */
334 int fr_set_dumpable(bool allow_core_dumps)
335 {
336         /*
337          *      If configured, turn core dumps off.
338          */
339         if (!allow_core_dumps) {
340 #ifdef HAVE_SYS_RESOURCE_H
341                 struct rlimit no_core;
342
343                 no_core.rlim_cur = 0;
344                 no_core.rlim_max = 0;
345
346                 if (setrlimit(RLIMIT_CORE, &no_core) < 0) {
347                         fr_strerror_printf("Failed disabling core dumps: %s", fr_syserror(errno));
348
349                         return -1;
350                 }
351 #endif
352                 return 0;
353         }
354
355         if (fr_set_dumpable_flag(true) < 0) return -1;
356
357         /*
358          *      Reset the core dump limits to their original value.
359          */
360 #ifdef HAVE_SYS_RESOURCE_H
361         if (setrlimit(RLIMIT_CORE, &core_limits) < 0) {
362                 fr_strerror_printf("Cannot update core dump limit: %s", fr_syserror(errno));
363
364                 return -1;
365         }
366 #endif
367         return 0;
368 }
369
370 /** Check to see if panic_action file is world writeable
371  *
372  * @return 0 if file is OK, else -1.
373  */
374 static int fr_fault_check_permissions(void)
375 {
376         char const *p, *q;
377         size_t len;
378         char filename[256];
379         struct stat statbuf;
380
381         /*
382          *      Try and guess which part of the command is the binary, and check to see if
383          *      it's world writeable, to try and save the admin from their own stupidity.
384          *
385          *      @fixme we should do this properly and take into account single and double
386          *      quotes.
387          */
388         if ((q = strchr(panic_action, ' '))) {
389                 /*
390                  *      need to use a static buffer, because mallocing memory in a signal handler
391                  *      is a bad idea and can result in deadlock.
392                  */
393                 len = snprintf(filename, sizeof(filename), "%.*s", (int)(q - panic_action), panic_action);
394                 if (is_truncated(len, sizeof(filename))) {
395                         fr_strerror_printf("Failed writing panic_action to temporary buffer (truncated)");
396                         return -1;
397                 }
398                 p = filename;
399         } else {
400                 p = panic_action;
401         }
402
403         if (stat(p, &statbuf) == 0) {
404 #ifdef S_IWOTH
405                 if ((statbuf.st_mode & S_IWOTH) != 0) {
406                         fr_strerror_printf("panic_action file \"%s\" is globally writable", p);
407                         return -1;
408                 }
409 #endif
410         }
411
412         return 0;
413 }
414
415 /** Prints a simple backtrace (if execinfo is available) and calls panic_action if set.
416  *
417  * @param sig caught
418  */
419 void fr_fault(int sig)
420 {
421         char cmd[sizeof(panic_action) + 20];
422         char *out = cmd;
423         size_t left = sizeof(cmd), ret;
424
425         char const *p = panic_action;
426         char const *q;
427
428         int code;
429
430         /*
431          *      Makes the backtraces slightly cleaner
432          */
433         memset(cmd, 0, sizeof(cmd));
434
435         FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
436
437         /*
438          *      Check for administrator sanity.
439          */
440         if (fr_fault_check_permissions() < 0) {
441                 FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror());
442                 goto finish;
443         }
444
445         /*
446          *      Run the callback if one was registered
447          */
448         if (panic_cb && (panic_cb(sig) < 0)) goto finish;
449
450         /*
451          *      Produce a simple backtrace - They've very basic but at least give us an
452          *      idea of the area of the code we hit the issue in.
453          *
454          *      See below in fr_fault_setup() and
455          *      https://sourceware.org/bugzilla/show_bug.cgi?id=16159
456          *      for why we only print backtraces in debug builds if we're using GLIBC.
457          */
458 #if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__))
459         {
460                 size_t frame_count, i;
461                 void *stack[MAX_BT_FRAMES];
462                 char **strings;
463
464                 frame_count = backtrace(stack, MAX_BT_FRAMES);
465
466                 FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count);
467
468                 /*
469                  *      Only use backtrace_symbols() if we don't have a logging fd.
470                  *      If the server has experienced memory corruption, there's
471                  *      a high probability that calling backtrace_symbols() which
472                  *      mallocs more memory, will fail.
473                  */
474                 if (fr_fault_log_fd < 0) {
475                         strings = backtrace_symbols(stack, frame_count);
476                         for (i = 0; i < frame_count; i++) {
477                                 FR_FAULT_LOG("%s", strings[i]);
478                         }
479                         free(strings);
480                 } else {
481                         backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd);
482                 }
483         }
484 #endif
485
486         /* No panic action set... */
487         if (panic_action[0] == '\0') {
488                 FR_FAULT_LOG("No panic action set");
489                 goto finish;
490         }
491
492         /* Substitute %p for the current PID (useful for attaching a debugger) */
493         while ((q = strstr(p, "%p"))) {
494                 out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid());
495                 if (left <= ret) {
496                 oob:
497                         FR_FAULT_LOG("Panic action too long");
498                         fr_exit_now(1);
499                 }
500                 left -= ret;
501                 p = q + 2;
502         }
503         if (strlen(p) >= left) goto oob;
504         strlcpy(out, p, left);
505
506         FR_FAULT_LOG("Calling: %s", cmd);
507
508         {
509                 bool disable = false;
510
511                 /*
512                  *      Here we temporarily enable the dumpable flag so if GBD or LLDB
513                  *      is called in the panic_action, they can pattach to the running
514                  *      process.
515                  */
516                 if (fr_get_dumpable_flag() == 0) {
517                         if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) {
518                                 FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror());
519                         } else {
520                                 disable = true;
521                         }
522                         FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1");
523                 }
524
525                 code = system(cmd);
526
527                 /*
528                  *      We only want to error out here, if dumpable was originally disabled
529                  *      and we managed to change the value to enabled, but failed
530                  *      setting it back to disabled.
531                  */
532                 if (disable) {
533                         FR_FAULT_LOG("Resetting PR_DUMPABLE to 0");
534                         if (fr_set_dumpable_flag(false) < 0) {
535                                 FR_FAULT_LOG("Failed reseting dumpable flag to off: %s", fr_strerror());
536                                 FR_FAULT_LOG("Exiting due to insecure process state");
537                                 fr_exit_now(1);
538                         }
539                 }
540         }
541
542         FR_FAULT_LOG("Panic action exited with %i", code);
543
544 finish:
545 #ifdef SIGUSR1
546         if (sig == SIGUSR1) {
547                 return;
548         }
549 #endif
550         fr_exit_now(1);
551 }
552
553 #ifdef SIGABRT
554 /** Work around debuggers which can't backtrace past the signal handler
555  *
556  * At least this provides us some information when we get talloc errors.
557  */
558 static void _fr_talloc_fault(char const *reason)
559 {
560         fr_fault_log("talloc abort: %s\n", reason);
561         fr_fault(SIGABRT);
562 }
563 #endif
564
565 /** Wrapper to pass talloc log output to our fr_fault_log function
566  *
567  */
568 static void _fr_talloc_log(char const *msg)
569 {
570         fr_fault_log("%s\n", msg);
571 }
572
573 /** Generate a talloc memory report for a context and print to stderr/stdout
574  *
575  * @param ctx to generate a report for, may be NULL in which case the root context is used.
576  */
577 int fr_log_talloc_report(TALLOC_CTX *ctx)
578 {
579         FILE *log;
580         int i = 0;
581         int fd;
582
583         fd = dup(fr_fault_log_fd);
584         if (fd < 0) {
585                 fr_strerror_printf("Couldn't write memory report, failed to dup log fd: %s", fr_syserror(errno));
586                 return -1;
587         }
588         log = fdopen(fd, "w");
589         if (!log) {
590                 close(fd);
591                 fr_strerror_printf("Couldn't write memory report, fdopen failed: %s", fr_syserror(errno));
592                 return -1;
593         }
594
595         if (!ctx) {
596                 fprintf(log, "Current state of talloced memory:\n");
597                 talloc_report_full(talloc_null_ctx, log);
598         } else {
599                 fprintf(log, "Talloc chunk lineage:\n");
600                 fprintf(log, "%p (%s)", ctx, talloc_get_name(ctx));
601                 while ((ctx = talloc_parent(ctx))) fprintf(log, " < %p (%s)", ctx, talloc_get_name(ctx));
602                 fprintf(log, "\n");
603
604                 do {
605                         fprintf(log, "Talloc context level %i:\n", i++);
606                         talloc_report_full(ctx, log);
607                 } while ((ctx = talloc_parent(ctx)) &&
608                          (talloc_parent(ctx) != talloc_autofree_ctx) && /* Stop before we hit the autofree ctx */
609                          (talloc_parent(ctx) != talloc_null_ctx));      /* Stop before we hit NULL ctx */
610         }
611
612         fclose(log);
613
614         return 0;
615 }
616
617 /** Signal handler to print out a talloc memory report
618  *
619  * @param sig caught
620  */
621 static void _fr_fault_mem_report(int sig)
622 {
623         FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig));
624
625         if (fr_log_talloc_report(NULL) < 0) fr_perror("memreport");
626 }
627
628 static int _fr_disable_null_tracking(UNUSED bool *p)
629 {
630         talloc_disable_null_tracking();
631         return 0;
632 }
633
634 /** Registers signal handlers to execute panic_action on fatal signal
635  *
636  * May be called multiple time to change the panic_action/program.
637  *
638  * @param cmd to execute on fault. If present %p will be substituted
639  *        for the parent PID before the command is executed, and %e
640  *        will be substituted for the currently running program.
641  * @param program Name of program currently executing (argv[0]).
642  * @return 0 on success -1 on failure.
643  */
644 int fr_fault_setup(char const *cmd, char const *program)
645 {
646         static bool setup = false;
647
648         char *out = panic_action;
649         size_t left = sizeof(panic_action), ret;
650
651         char const *p = cmd;
652         char const *q;
653
654         if (cmd) {
655                 /* Substitute %e for the current program */
656                 while ((q = strstr(p, "%e"))) {
657                         out += ret = snprintf(out, left, "%.*s%s", (int) (q - p), p, program ? program : "");
658                         if (left <= ret) {
659                         oob:
660                                 fr_strerror_printf("Panic action too long");
661                                 return -1;
662                         }
663                         left -= ret;
664                         p = q + 2;
665                 }
666                 if (strlen(p) >= left) goto oob;
667                 strlcpy(out, p, left);
668         } else {
669                 *panic_action = '\0';
670         }
671
672         /*
673          *      Check for administrator sanity.
674          */
675         if (fr_fault_check_permissions() < 0) return -1;
676
677         /* Unsure what the side effects of changing the signal handler mid execution might be */
678         if (!setup) {
679                 if (cmd) {
680 #ifdef SIGSEGV
681                         if (fr_set_signal(SIGSEGV, fr_fault) < 0) return -1;
682 #endif
683 #ifdef SIGBUS
684                         if (fr_set_signal(SIGBUS, fr_fault) < 0) return -1;
685 #endif
686 #ifdef SIGABRT
687                         if (fr_set_signal(SIGABRT, fr_fault) < 0) return -1;
688                         /*
689                          *  Use this instead of abort so we get a
690                          *  full backtrace with broken versions of LLDB
691                          */
692                         talloc_set_abort_fn(_fr_talloc_fault);
693 #endif
694 #ifdef SIGFPE
695                         if (fr_set_signal(SIGFPE, fr_fault) < 0) return -1;
696 #endif
697                 }
698 #ifdef SIGUSR1
699                 if (fr_set_signal(SIGUSR1, fr_fault) < 0) return -1;
700 #endif
701
702 #ifdef SIGUSR2
703                 if (fr_set_signal(SIGUSR2, _fr_fault_mem_report) < 0) return -1;
704 #endif
705
706                 /*
707                  *  Setup the default logger
708                  */
709                 if (!fr_fault_log) fr_fault_set_log_fn(NULL);
710                 talloc_set_log_fn(_fr_talloc_log);
711
712                 /*
713                  *  Needed for memory reports
714                  */
715                 {
716                         TALLOC_CTX *tmp;
717                         bool *marker;
718
719                         tmp = talloc(NULL, bool);
720                         talloc_null_ctx = talloc_parent(tmp);
721                         talloc_free(tmp);
722
723                         /*
724                          *  Disable null tracking on exit, else valgrind complains
725                          */
726                         talloc_autofree_ctx = talloc_autofree_context();
727                         marker = talloc(talloc_autofree_ctx, bool);
728                         talloc_set_destructor(marker, _fr_disable_null_tracking);
729                 }
730
731 #if defined(HAVE_MALLOPT) && !defined(NDEBUG)
732                 /*
733                  *  If were using glibc malloc > 2.4 this scribbles over
734                  *  uninitialised and freed memory, to make memory issues easier
735                  *  to track down.
736                  */
737                 if (!getenv("TALLOC_FREE_FILL")) mallopt(M_PERTURB, 0x42);
738                 mallopt(M_CHECK_ACTION, 3);
739 #endif
740
741 #if defined(HAVE_EXECINFO) && defined(__GNUC__) && !defined(NDEBUG)
742                /*
743                 *  We need to pre-load lgcc_s, else we can get into a deadlock
744                 *  in fr_fault, as backtrace() attempts to dlopen it.
745                 *
746                 *  Apparently there's a performance impact of loading lgcc_s,
747                 *  so only do it if this is a debug build.
748                 *
749                 *  See: https://sourceware.org/bugzilla/show_bug.cgi?id=16159
750                 */
751                 {
752                         void *stack[10];
753
754                         backtrace(stack, 10);
755                 }
756 #endif
757         }
758         setup = true;
759
760         return 0;
761 }
762
763 /** Set a callback to be called before fr_fault()
764  *
765  * @param func to execute. If callback returns < 0
766  *      fr_fault will exit before running panic_action code.
767  */
768 void fr_fault_set_cb(fr_fault_cb_t func)
769 {
770         panic_cb = func;
771 };
772
773 /** Default logger, logs output to stderr
774  *
775  */
776 static void CC_HINT(format (printf, 1, 2)) _fr_fault_log(char const *msg, ...)
777 {
778         va_list ap;
779
780         va_start(ap, msg);
781         vfprintf(stderr, msg, ap);
782         va_end(ap);
783 }
784
785
786 /** Set a file descriptor to log panic_action output to.
787  *
788  * @param func to call to output log messages.
789  */
790 void fr_fault_set_log_fn(fr_fault_log_t func)
791 {
792         fr_fault_log = func ? func : _fr_fault_log;
793 }
794
795 /** Set a file descriptor to log memory reports to.
796  *
797  * @param fd to write output to.
798  */
799 void fr_fault_set_log_fd(int fd)
800 {
801         fr_fault_log_fd = fd;
802 }
803
804
805 #ifdef WITH_VERIFY_PTR
806
807 /*
808  *      Verify a VALUE_PAIR
809  */
810 inline void fr_verify_vp(char const *file, int line, VALUE_PAIR const *vp)
811 {
812         if (!vp) {
813                 FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR pointer was NULL", file, line);
814                 fr_assert(0);
815                 fr_exit_now(0);
816         }
817
818         (void) talloc_get_type_abort(vp, VALUE_PAIR);
819
820         if (vp->data.ptr) switch (vp->da->type) {
821         case PW_TYPE_OCTETS:
822         case PW_TYPE_TLV:
823         {
824                 size_t len;
825                 TALLOC_CTX *parent;
826
827                 if (!talloc_get_type(vp->data.ptr, uint8_t)) {
828                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
829                                      "uint8_t but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
830                         (void) talloc_get_type_abort(vp->data.ptr, uint8_t);
831                 }
832
833                 len = talloc_array_length(vp->vp_octets);
834                 if (vp->length > len) {
835                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
836                                      "uint8_t data buffer length %zu\n", file, line, vp->da->name, vp->length, len);
837                         fr_assert(0);
838                         fr_exit_now(1);
839                 }
840
841                 parent = talloc_parent(vp->data.ptr);
842                 if (parent != vp) {
843                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer is not "
844                                      "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
845                                      file, line, vp->da->name,
846                                      vp, parent, parent ? talloc_get_name(parent) : "NULL");
847                         fr_assert(0);
848                         fr_exit_now(1);
849                 }
850         }
851                 break;
852
853         case PW_TYPE_STRING:
854         {
855                 size_t len;
856                 TALLOC_CTX *parent;
857
858                 if (!talloc_get_type(vp->data.ptr, char)) {
859                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" data buffer type should be "
860                                      "char but is %s\n", file, line, vp->da->name, talloc_get_name(vp->data.ptr));
861                         (void) talloc_get_type_abort(vp->data.ptr, char);
862                 }
863
864                 len = (talloc_array_length(vp->vp_strvalue) - 1);
865                 if (vp->length > len) {
866                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" length %zu is greater than "
867                                      "char buffer length %zu\n", file, line, vp->da->name, vp->length, len);
868                         fr_assert(0);
869                         fr_exit_now(1);
870                 }
871
872                 if (vp->vp_strvalue[vp->length] != '\0') {
873                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" char buffer not \\0 "
874                                      "terminated\n", file, line, vp->da->name);
875                         fr_assert(0);
876                         fr_exit_now(1);
877                 }
878
879                 parent = talloc_parent(vp->data.ptr);
880                 if (parent != vp) {
881                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: VALUE_PAIR \"%s\" uint8_t buffer is not "
882                                      "parented by VALUE_PAIR %p, instead parented by %p (%s)\n",
883                                      file, line, vp->da->name,
884                                      vp, parent, parent ? talloc_get_name(parent) : "NULL");
885                         fr_assert(0);
886                         fr_exit_now(1);
887                 }
888         }
889                 break;
890
891         default:
892                 break;
893         }
894 }
895
896 /*
897  *      Verify a pair list
898  */
899 void fr_verify_list(char const *file, int line, TALLOC_CTX *expected, VALUE_PAIR *vps)
900 {
901         vp_cursor_t cursor;
902         VALUE_PAIR *vp;
903         TALLOC_CTX *parent;
904
905         for (vp = fr_cursor_init(&cursor, &vps);
906              vp;
907              vp = fr_cursor_next(&cursor)) {
908                 VERIFY_VP(vp);
909
910                 parent = talloc_parent(vp);
911                 if (expected && (parent != expected)) {
912                         FR_FAULT_LOG("CONSISTENCY CHECK FAILED %s[%u]: Expected VALUE_PAIR \"%s\" to be parented "
913                                      "by %p (%s), instead parented by %p (%s)\n",
914                                      file, line, vp->da->name,
915                                      expected, talloc_get_name(expected),
916                                      parent, parent ? talloc_get_name(parent) : "NULL");
917
918                         fr_log_talloc_report(expected);
919                         if (parent) fr_log_talloc_report(parent);
920
921                         assert(0);
922                 }
923
924         }
925 }
926 #endif
927
928 bool fr_assert_cond(char const *file, int line, char const *expr, bool cond)
929 {
930         if (!cond) {
931                 FR_FAULT_LOG("SOFT ASSERT FAILED %s[%u]: %s", file, line, expr);
932 #if !defined(NDEBUG) && defined(SIGUSR1)
933                 fr_fault(SIGUSR1);
934 #endif
935                 return false;
936         }
937
938         return cond;
939 }
940
941 /** Exit possibly printing a message about why we're exiting.
942  *
943  * Use the fr_exit(status) macro instead of calling this function
944  * directly.
945  *
946  * @param file where fr_exit() was called.
947  * @param line where fr_exit() was called.
948  * @param status we're exiting with.
949  */
950 void NEVER_RETURNS _fr_exit(char const *file, int line, int status)
951 {
952 #ifndef NDEBUG
953         char const *error = fr_strerror();
954
955         if (error && (status != 0)) {
956                 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u].  Last error was: %s", status, file, line, error);
957         } else {
958                 FR_FAULT_LOG("EXIT(%i) CALLED %s[%u]", status, file, line);
959         }
960 #endif
961         fprintf(stderr, "If running under a debugger it should break <<here>>");
962         fflush(stderr);
963
964         fr_debug_break();       /* If running under GDB we'll break here */
965
966         exit(status);
967 }
968
969 /** Exit possibly printing a message about why we're exiting.
970  *
971  * Use the fr_exit_now(status) macro instead of calling this function
972  * directly.
973  *
974  * @param file where fr_exit_now() was called.
975  * @param line where fr_exit_now() was called.
976  * @param status we're exiting with.
977  */
978 void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status)
979 {
980 #ifndef NDEBUG
981         char const *error = fr_strerror();
982
983         if (error && (status != 0)) {
984                 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u].  Last error was: %s", status, file, line, error);
985         } else {
986                 FR_FAULT_LOG("_EXIT(%i) CALLED %s[%u]", status, file, line);
987         }
988 #endif
989         fprintf(stderr, "If running under a debugger it should break <<here>>\n");
990         fflush(stderr);
991
992         fr_debug_break();       /* If running under GDB we'll break here */
993
994         _exit(status);
995 }