Mark ChangeLog
[official-gcc.git] / libmudflap / mf-runtime.c
blob96a396ef3199674a09ae1dfd3832a221ff553604
1 /* Mudflap: narrow-pointer bounds-checking by tree rewriting.
2 Copyright (C) 2002-2013 Free Software Foundation, Inc.
3 Contributed by Frank Ch. Eigler <fche@redhat.com>
4 and Graydon Hoare <graydon@redhat.com>
5 Splay Tree code originally by Mark Mitchell <mark@markmitchell.com>,
6 adapted from libiberty.
8 This file is part of GCC.
10 GCC is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 3, or (at your option) any later
13 version.
15 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
20 Under Section 7 of GPL version 3, you are granted additional
21 permissions described in the GCC Runtime Library Exception, version
22 3.1, as published by the Free Software Foundation.
24 You should have received a copy of the GNU General Public License and
25 a copy of the GCC Runtime Library Exception along with this program;
26 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
27 <http://www.gnu.org/licenses/>. */
29 #include "config.h"
31 /* These attempt to coax various unix flavours to declare all our
32 needed tidbits in the system headers. */
33 #if !defined(__FreeBSD__) && !defined(__APPLE__)
34 #define _POSIX_SOURCE
35 #endif /* Some BSDs break <sys/socket.h> if this is defined. */
36 #define _GNU_SOURCE
37 #define _XOPEN_SOURCE
38 #define _BSD_TYPES
39 #define __EXTENSIONS__
40 #define _ALL_SOURCE
41 #define _LARGE_FILE_API
42 #define _XOPEN_SOURCE_EXTENDED 1
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <unistd.h>
50 #ifdef HAVE_EXECINFO_H
51 #include <execinfo.h>
52 #endif
53 #ifdef HAVE_SIGNAL_H
54 #include <signal.h>
55 #endif
56 #include <assert.h>
58 #include <string.h>
59 #include <limits.h>
60 #include <sys/types.h>
61 #include <signal.h>
62 #include <errno.h>
63 #include <ctype.h>
65 #include "mf-runtime.h"
66 #include "mf-impl.h"
69 /* ------------------------------------------------------------------------ */
70 /* Splay-tree implementation. */
72 typedef uintptr_t mfsplay_tree_key;
73 typedef void *mfsplay_tree_value;
75 /* Forward declaration for a node in the tree. */
76 typedef struct mfsplay_tree_node_s *mfsplay_tree_node;
78 /* The type of a function used to iterate over the tree. */
79 typedef int (*mfsplay_tree_foreach_fn) (mfsplay_tree_node, void *);
81 /* The nodes in the splay tree. */
82 struct mfsplay_tree_node_s
84 /* Data. */
85 mfsplay_tree_key key;
86 mfsplay_tree_value value;
87 /* Children. */
88 mfsplay_tree_node left;
89 mfsplay_tree_node right;
90 /* XXX: The addition of a parent pointer may eliminate some recursion. */
93 /* The splay tree itself. */
94 struct mfsplay_tree_s
96 /* The root of the tree. */
97 mfsplay_tree_node root;
99 /* The last key value for which the tree has been splayed, but not
100 since modified. */
101 mfsplay_tree_key last_splayed_key;
102 int last_splayed_key_p;
104 /* Statistics. */
105 unsigned num_keys;
107 /* Traversal recursion control flags. */
108 unsigned max_depth;
109 unsigned depth;
110 unsigned rebalance_p;
112 typedef struct mfsplay_tree_s *mfsplay_tree;
114 static mfsplay_tree mfsplay_tree_new (void);
115 static mfsplay_tree_node mfsplay_tree_insert (mfsplay_tree, mfsplay_tree_key, mfsplay_tree_value);
116 static void mfsplay_tree_remove (mfsplay_tree, mfsplay_tree_key);
117 static mfsplay_tree_node mfsplay_tree_lookup (mfsplay_tree, mfsplay_tree_key);
118 static mfsplay_tree_node mfsplay_tree_predecessor (mfsplay_tree, mfsplay_tree_key);
119 static mfsplay_tree_node mfsplay_tree_successor (mfsplay_tree, mfsplay_tree_key);
120 static int mfsplay_tree_foreach (mfsplay_tree, mfsplay_tree_foreach_fn, void *);
121 static void mfsplay_tree_rebalance (mfsplay_tree sp);
123 /* ------------------------------------------------------------------------ */
124 /* Utility macros */
126 #define CTOR __attribute__ ((constructor))
127 #define DTOR __attribute__ ((destructor))
130 /* Codes to describe the context in which a violation occurs. */
131 #define __MF_VIOL_UNKNOWN 0
132 #define __MF_VIOL_READ 1
133 #define __MF_VIOL_WRITE 2
134 #define __MF_VIOL_REGISTER 3
135 #define __MF_VIOL_UNREGISTER 4
136 #define __MF_VIOL_WATCH 5
138 /* Protect against recursive calls. */
140 static void
141 begin_recursion_protect1 (const char *pf)
143 if (__mf_get_state () == reentrant)
145 write (2, "mf: erroneous reentrancy detected in `", 38);
146 write (2, pf, strlen(pf));
147 write (2, "'\n", 2); \
148 abort ();
150 __mf_set_state (reentrant);
153 #define BEGIN_RECURSION_PROTECT() \
154 begin_recursion_protect1 (__PRETTY_FUNCTION__)
156 #define END_RECURSION_PROTECT() \
157 __mf_set_state (active)
159 /* ------------------------------------------------------------------------ */
160 /* Required globals. */
162 #define LOOKUP_CACHE_MASK_DFL 1023
163 #define LOOKUP_CACHE_SIZE_MAX 65536 /* Allows max CACHE_MASK 0xFFFF */
164 #define LOOKUP_CACHE_SHIFT_DFL 2
166 struct __mf_cache __mf_lookup_cache [LOOKUP_CACHE_SIZE_MAX];
167 uintptr_t __mf_lc_mask = LOOKUP_CACHE_MASK_DFL;
168 unsigned char __mf_lc_shift = LOOKUP_CACHE_SHIFT_DFL;
169 #define LOOKUP_CACHE_SIZE (__mf_lc_mask + 1)
171 struct __mf_options __mf_opts;
172 int __mf_starting_p = 1;
174 #ifdef LIBMUDFLAPTH
175 #if defined(HAVE_TLS) && !defined(USE_EMUTLS)
176 __thread enum __mf_state_enum __mf_state_1 = reentrant;
177 #endif
178 #else
179 enum __mf_state_enum __mf_state_1 = reentrant;
180 #endif
182 #ifdef LIBMUDFLAPTH
183 pthread_mutex_t __mf_biglock =
184 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
185 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
186 #else
187 PTHREAD_MUTEX_INITIALIZER;
188 #endif
189 #endif
191 /* Use HAVE_PTHREAD_H here instead of LIBMUDFLAPTH, so that even
192 the libmudflap.la (no threading support) can diagnose whether
193 the application is linked with -lpthread. See __mf_usage() below. */
194 #if HAVE_PTHREAD_H
195 #ifdef _POSIX_THREADS
196 #pragma weak pthread_join
197 #else
198 #define pthread_join NULL
199 #endif
200 #endif
203 /* ------------------------------------------------------------------------ */
204 /* stats-related globals. */
206 static unsigned long __mf_count_check;
207 static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX];
208 static unsigned long __mf_count_register;
209 static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1];
210 static unsigned long __mf_count_unregister;
211 static unsigned long __mf_total_unregister_size;
212 static unsigned long __mf_count_violation [__MF_VIOL_WATCH+1];
213 static unsigned long __mf_sigusr1_received;
214 static unsigned long __mf_sigusr1_handled;
215 /* not static */ unsigned long __mf_reentrancy;
216 #ifdef LIBMUDFLAPTH
217 /* not static */ unsigned long __mf_lock_contention;
218 #endif
221 /* ------------------------------------------------------------------------ */
222 /* mode-check-related globals. */
224 typedef struct __mf_object
226 uintptr_t low, high; /* __mf_register parameters */
227 const char *name;
228 char type; /* __MF_TYPE_something */
229 char watching_p; /* Trigger a VIOL_WATCH on access? */
230 unsigned read_count; /* Number of times __mf_check/read was called on this object. */
231 unsigned write_count; /* Likewise for __mf_check/write. */
232 unsigned liveness; /* A measure of recent checking activity. */
233 unsigned description_epoch; /* Last epoch __mf_describe_object printed this. */
235 uintptr_t alloc_pc;
236 struct timeval alloc_time;
237 char **alloc_backtrace;
238 size_t alloc_backtrace_size;
239 #ifdef LIBMUDFLAPTH
240 pthread_t alloc_thread;
241 #endif
243 int deallocated_p;
244 uintptr_t dealloc_pc;
245 struct timeval dealloc_time;
246 char **dealloc_backtrace;
247 size_t dealloc_backtrace_size;
248 #ifdef LIBMUDFLAPTH
249 pthread_t dealloc_thread;
250 #endif
251 } __mf_object_t;
253 /* Live objects: splay trees, separated by type, ordered on .low (base address). */
254 /* Actually stored as static vars within lookup function below. */
256 /* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */
257 static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */
258 static __mf_object_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX];
261 /* ------------------------------------------------------------------------ */
262 /* Forward function declarations */
264 void __mf_init () CTOR;
265 static void __mf_sigusr1_respond ();
266 static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high,
267 __mf_object_t **objs, unsigned max_objs);
268 static unsigned __mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high,
269 __mf_object_t **objs, unsigned max_objs, int type);
270 static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high,
271 __mf_object_t **objs, unsigned max_objs);
272 static void __mf_adapt_cache ();
273 static void __mf_describe_object (__mf_object_t *obj);
274 static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
275 static mfsplay_tree __mf_object_tree (int type);
276 static void __mf_link_object (__mf_object_t *node);
277 static void __mf_unlink_object (__mf_object_t *node);
280 /* ------------------------------------------------------------------------ */
281 /* Configuration engine */
283 static void
284 __mf_set_default_options ()
286 memset (& __mf_opts, 0, sizeof (__mf_opts));
288 __mf_opts.adapt_cache = 1000003;
289 __mf_opts.abbreviate = 1;
290 __mf_opts.verbose_violations = 1;
291 __mf_opts.free_queue_length = 4;
292 __mf_opts.persistent_count = 100;
293 __mf_opts.crumple_zone = 32;
294 __mf_opts.backtrace = 4;
295 __mf_opts.timestamps = 1;
296 __mf_opts.mudflap_mode = mode_check;
297 __mf_opts.violation_mode = viol_nop;
298 #ifdef HAVE___LIBC_FREERES
299 __mf_opts.call_libc_freeres = 1;
300 #endif
301 __mf_opts.heur_std_data = 1;
302 #ifdef LIBMUDFLAPTH
303 __mf_opts.thread_stack = 0;
304 #endif
306 /* PR41443: Beware that the above flags will be applied to
307 setuid/setgid binaries, and cannot be overriden with
308 $MUDFLAP_OPTIONS. So the defaults must be non-exploitable.
310 Should we consider making the default violation_mode something
311 harsher than viol_nop? OTOH, glibc's MALLOC_CHECK_ is disabled
312 by default for these same programs. */
315 static struct mudoption
317 char *name;
318 char *description;
319 enum
321 set_option,
322 read_integer_option,
323 } type;
324 unsigned value;
325 unsigned *target;
327 options [] =
329 {"mode-nop",
330 "mudflaps do nothing",
331 set_option, (unsigned)mode_nop, (unsigned *)&__mf_opts.mudflap_mode},
332 {"mode-populate",
333 "mudflaps populate object tree",
334 set_option, (unsigned)mode_populate, (unsigned *)&__mf_opts.mudflap_mode},
335 {"mode-check",
336 "mudflaps check for memory violations",
337 set_option, (unsigned)mode_check, (unsigned *)&__mf_opts.mudflap_mode},
338 {"mode-violate",
339 "mudflaps always cause violations (diagnostic)",
340 set_option, (unsigned)mode_violate, (unsigned *)&__mf_opts.mudflap_mode},
342 {"viol-nop",
343 "violations do not change program execution",
344 set_option, (unsigned)viol_nop, (unsigned *)&__mf_opts.violation_mode},
345 {"viol-abort",
346 "violations cause a call to abort()",
347 set_option, (unsigned)viol_abort, (unsigned *)&__mf_opts.violation_mode},
348 {"viol-segv",
349 "violations are promoted to SIGSEGV signals",
350 set_option, (unsigned)viol_segv, (unsigned *)&__mf_opts.violation_mode},
351 {"viol-gdb",
352 "violations fork a gdb process attached to current program",
353 set_option, (unsigned)viol_gdb, (unsigned *)&__mf_opts.violation_mode},
354 {"trace-calls",
355 "trace calls to mudflap runtime library",
356 set_option, 1, &__mf_opts.trace_mf_calls},
357 {"verbose-trace",
358 "trace internal events within mudflap runtime library",
359 set_option, 1, &__mf_opts.verbose_trace},
360 {"collect-stats",
361 "collect statistics on mudflap's operation",
362 set_option, 1, &__mf_opts.collect_stats},
363 #ifdef SIGUSR1
364 {"sigusr1-report",
365 "print report upon SIGUSR1",
366 set_option, 1, &__mf_opts.sigusr1_report},
367 #endif
368 {"internal-checking",
369 "perform more expensive internal checking",
370 set_option, 1, &__mf_opts.internal_checking},
371 {"print-leaks",
372 "print any memory leaks at program shutdown",
373 set_option, 1, &__mf_opts.print_leaks},
374 #ifdef HAVE___LIBC_FREERES
375 {"libc-freeres",
376 "call glibc __libc_freeres at shutdown for better leak data",
377 set_option, 1, &__mf_opts.call_libc_freeres},
378 #endif
379 {"check-initialization",
380 "detect uninitialized object reads",
381 set_option, 1, &__mf_opts.check_initialization},
382 {"verbose-violations",
383 "print verbose messages when memory violations occur",
384 set_option, 1, &__mf_opts.verbose_violations},
385 {"abbreviate",
386 "abbreviate repetitive listings",
387 set_option, 1, &__mf_opts.abbreviate},
388 {"timestamps",
389 "track object lifetime timestamps",
390 set_option, 1, &__mf_opts.timestamps},
391 {"ignore-reads",
392 "ignore read accesses - assume okay",
393 set_option, 1, &__mf_opts.ignore_reads},
394 {"wipe-stack",
395 "wipe stack objects at unwind",
396 set_option, 1, &__mf_opts.wipe_stack},
397 {"wipe-heap",
398 "wipe heap objects at free",
399 set_option, 1, &__mf_opts.wipe_heap},
400 {"heur-proc-map",
401 "support /proc/self/map heuristics",
402 set_option, 1, &__mf_opts.heur_proc_map},
403 {"heur-stack-bound",
404 "enable a simple upper stack bound heuristic",
405 set_option, 1, &__mf_opts.heur_stack_bound},
406 {"heur-start-end",
407 "support _start.._end heuristics",
408 set_option, 1, &__mf_opts.heur_start_end},
409 {"heur-stdlib",
410 "register standard library data (argv, errno, stdin, ...)",
411 set_option, 1, &__mf_opts.heur_std_data},
412 {"free-queue-length",
413 "queue N deferred free() calls before performing them",
414 read_integer_option, 0, &__mf_opts.free_queue_length},
415 {"persistent-count",
416 "keep a history of N unregistered regions",
417 read_integer_option, 0, &__mf_opts.persistent_count},
418 {"crumple-zone",
419 "surround allocations with crumple zones of N bytes",
420 read_integer_option, 0, &__mf_opts.crumple_zone},
421 /* XXX: not type-safe.
422 {"lc-mask",
423 "set lookup cache size mask to N (2**M - 1)",
424 read_integer_option, 0, (int *)(&__mf_lc_mask)},
425 {"lc-shift",
426 "set lookup cache pointer shift",
427 read_integer_option, 0, (int *)(&__mf_lc_shift)},
429 {"lc-adapt",
430 "adapt mask/shift parameters after N cache misses",
431 read_integer_option, 1, &__mf_opts.adapt_cache},
432 {"backtrace",
433 "keep an N-level stack trace of each call context",
434 read_integer_option, 0, &__mf_opts.backtrace},
435 #ifdef LIBMUDFLAPTH
436 {"thread-stack",
437 "override thread stacks allocation: N kB",
438 read_integer_option, 0, &__mf_opts.thread_stack},
439 #endif
440 {0, 0, set_option, 0, NULL}
443 static void
444 __mf_usage ()
446 struct mudoption *opt;
448 fprintf (stderr,
449 "This is a %s%sGCC \"mudflap\" memory-checked binary.\n"
450 "Mudflap is Copyright (C) 2002-2013 Free Software Foundation, Inc.\n"
451 "\n"
452 "Unless setuid, a program's mudflap options be set by an environment variable:\n"
453 "\n"
454 "$ export MUDFLAP_OPTIONS='<options>'\n"
455 "$ <mudflapped_program>\n"
456 "\n"
457 "where <options> is a space-separated list of \n"
458 "any of the following options. Use `-no-OPTION' to disable options.\n"
459 "\n",
460 #if HAVE_PTHREAD_H
461 (pthread_join ? "multi-threaded " : "single-threaded "),
462 #else
464 #endif
465 #if LIBMUDFLAPTH
466 "thread-aware "
467 #else
468 "thread-unaware "
469 #endif
471 /* XXX: The multi-threaded thread-unaware combination is bad. */
473 for (opt = options; opt->name; opt++)
475 int default_p = (opt->value == * opt->target);
477 switch (opt->type)
479 char buf[128];
480 case set_option:
481 fprintf (stderr, "-%-23.23s %s", opt->name, opt->description);
482 if (default_p)
483 fprintf (stderr, " [active]\n");
484 else
485 fprintf (stderr, "\n");
486 break;
487 case read_integer_option:
488 strncpy (buf, opt->name, 128);
489 strncpy (buf + strlen (opt->name), "=N", 2);
490 fprintf (stderr, "-%-23.23s %s", buf, opt->description);
491 fprintf (stderr, " [%d]\n", * opt->target);
492 break;
493 default: abort();
497 fprintf (stderr, "\n");
502 __mf_set_options (const char *optstr)
504 int rc;
505 LOCKTH ();
506 BEGIN_RECURSION_PROTECT ();
507 rc = __mfu_set_options (optstr);
508 /* XXX: It's not really that easy. A change to a bunch of parameters
509 can require updating auxiliary state or risk crashing:
510 free_queue_length, crumple_zone ... */
511 END_RECURSION_PROTECT ();
512 UNLOCKTH ();
513 return rc;
518 __mfu_set_options (const char *optstr)
520 struct mudoption *opts = 0;
521 char *nxt = 0;
522 long tmp = 0;
523 int rc = 0;
524 const char *saved_optstr = optstr;
526 /* XXX: bounds-check for optstr! */
528 while (*optstr)
530 switch (*optstr) {
531 case ' ':
532 case '\t':
533 case '\n':
534 optstr++;
535 break;
537 case '-':
538 if (*optstr+1)
540 int negate = 0;
541 optstr++;
543 if (*optstr == '?' ||
544 strncmp (optstr, "help", 4) == 0)
546 /* Caller will print help and exit. */
547 return -1;
550 if (strncmp (optstr, "no-", 3) == 0)
552 negate = 1;
553 optstr = & optstr[3];
556 for (opts = options; opts->name; opts++)
558 if (strncmp (optstr, opts->name, strlen (opts->name)) == 0)
560 optstr += strlen (opts->name);
561 assert (opts->target);
562 switch (opts->type)
564 case set_option:
565 if (negate)
566 *(opts->target) = 0;
567 else
568 *(opts->target) = opts->value;
569 break;
570 case read_integer_option:
571 if (! negate && (*optstr == '=' && *(optstr+1)))
573 optstr++;
574 tmp = strtol (optstr, &nxt, 10);
575 if ((optstr != nxt) && (tmp != LONG_MAX))
577 optstr = nxt;
578 *(opts->target) = (int)tmp;
581 else if (negate)
582 * opts->target = 0;
583 break;
588 break;
590 default:
591 fprintf (stderr,
592 "warning: unrecognized string '%s' in mudflap options\n",
593 optstr);
594 optstr += strlen (optstr);
595 rc = -1;
596 break;
600 /* Special post-processing: bound __mf_lc_mask and free_queue_length for security. */
601 __mf_lc_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
602 __mf_opts.free_queue_length &= (__MF_FREEQ_MAX - 1);
604 /* Clear the lookup cache, in case the parameters got changed. */
605 /* XXX: race */
606 memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
607 /* void slot 0 */
608 __mf_lookup_cache[0].low = MAXPTR;
610 TRACE ("set options from `%s'\n", saved_optstr);
612 /* Call this unconditionally, in case -sigusr1-report was toggled. */
613 __mf_sigusr1_respond ();
615 return rc;
619 #ifdef PIC
621 void
622 __mf_resolve_single_dynamic (struct __mf_dynamic_entry *e)
624 char *err;
626 assert (e);
627 if (e->pointer) return;
629 #if HAVE_DLVSYM
630 if (e->version != NULL && e->version[0] != '\0') /* non-null/empty */
631 e->pointer = dlvsym (RTLD_NEXT, e->name, e->version);
632 else
633 #endif
634 e->pointer = dlsym (RTLD_NEXT, e->name);
636 err = dlerror ();
638 if (err)
640 fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n",
641 e->name, err);
642 abort ();
644 if (! e->pointer)
646 fprintf (stderr, "mf: dlsym(\"%s\") = NULL\n", e->name);
647 abort ();
652 static void
653 __mf_resolve_dynamics ()
655 int i;
656 for (i = 0; i < dyn_INITRESOLVE; i++)
657 __mf_resolve_single_dynamic (& __mf_dynamic[i]);
661 /* NB: order must match enums in mf-impl.h */
662 struct __mf_dynamic_entry __mf_dynamic [] =
664 {NULL, "calloc", NULL},
665 {NULL, "free", NULL},
666 {NULL, "malloc", NULL},
667 {NULL, "mmap", NULL},
668 #ifdef HAVE_MMAP64
669 {NULL, "mmap64", NULL},
670 #endif
671 {NULL, "munmap", NULL},
672 {NULL, "realloc", NULL},
673 {NULL, "DUMMY", NULL}, /* dyn_INITRESOLVE */
674 #ifdef LIBMUDFLAPTH
675 {NULL, "pthread_create", PTHREAD_CREATE_VERSION},
676 {NULL, "pthread_join", NULL},
677 {NULL, "pthread_exit", NULL}
678 #endif
681 #endif /* PIC */
685 /* ------------------------------------------------------------------------ */
687 /* Lookup & manage automatic initialization of the five or so splay trees. */
688 static mfsplay_tree
689 __mf_object_tree (int type)
691 static mfsplay_tree trees [__MF_TYPE_MAX+1];
692 assert (type >= 0 && type <= __MF_TYPE_MAX);
693 if (UNLIKELY (trees[type] == NULL))
694 trees[type] = mfsplay_tree_new ();
695 return trees[type];
699 /* not static */void
700 __mf_init ()
702 char *ov = 0;
704 /* Return if initialization has already been done. */
705 if (LIKELY (__mf_starting_p == 0))
706 return;
708 #if defined(__FreeBSD__) && defined(LIBMUDFLAPTH)
709 pthread_self();
710 LOCKTH ();
711 UNLOCKTH ();
712 #endif /* Prime mutex which calls calloc upon first lock to avoid deadlock. */
714 /* This initial bootstrap phase requires that __mf_starting_p = 1. */
715 #ifdef PIC
716 __mf_resolve_dynamics ();
717 #endif
718 __mf_starting_p = 0;
720 __mf_set_state (active);
722 __mf_set_default_options ();
724 if (getuid () == geteuid () && getgid () == getegid ()) /* PR41433, not setuid */
725 ov = getenv ("MUDFLAP_OPTIONS");
726 if (ov)
728 int rc = __mfu_set_options (ov);
729 if (rc < 0)
731 __mf_usage ();
732 exit (1);
736 /* Initialize to a non-zero description epoch. */
737 __mf_describe_object (NULL);
739 #define REG_RESERVED(obj) \
740 __mf_register (& obj, sizeof(obj), __MF_TYPE_NOACCESS, # obj)
742 REG_RESERVED (__mf_lookup_cache);
743 REG_RESERVED (__mf_lc_mask);
744 REG_RESERVED (__mf_lc_shift);
745 /* XXX: others of our statics? */
747 /* Prevent access to *NULL. */
748 __mf_register (MINPTR, 1, __MF_TYPE_NOACCESS, "NULL");
749 __mf_lookup_cache[0].low = (uintptr_t) -1;
755 __wrap_main (int argc, char* argv[])
757 extern char **environ;
758 extern int main ();
759 extern int __real_main ();
760 static int been_here = 0;
762 if (__mf_opts.heur_std_data && ! been_here)
764 unsigned i;
766 been_here = 1;
767 __mf_register (argv, sizeof(char *)*(argc+1), __MF_TYPE_STATIC, "argv[]");
768 for (i=0; i<argc; i++)
770 unsigned j = strlen (argv[i]);
771 __mf_register (argv[i], j+1, __MF_TYPE_STATIC, "argv element");
774 for (i=0; ; i++)
776 char *e = environ[i];
777 unsigned j;
778 if (e == NULL) break;
779 j = strlen (environ[i]);
780 __mf_register (environ[i], j+1, __MF_TYPE_STATIC, "environ element");
782 __mf_register (environ, sizeof(char *)*(i+1), __MF_TYPE_STATIC, "environ[]");
784 __mf_register (& errno, sizeof (errno), __MF_TYPE_STATIC, "errno area");
786 #if !(defined(__sun__) && defined(__svr4__))
787 /* Conflicts with the automatic registration of __iob[]. */
788 __mf_register (stdin, sizeof (*stdin), __MF_TYPE_STATIC, "stdin");
789 __mf_register (stdout, sizeof (*stdout), __MF_TYPE_STATIC, "stdout");
790 __mf_register (stderr, sizeof (*stderr), __MF_TYPE_STATIC, "stderr");
791 #endif
793 /* Make some effort to register ctype.h static arrays. */
794 #if defined(__sun__) && defined(__svr4__)
795 /* __ctype[] is declared without size, but MB_CUR_MAX is the last
796 member. There seems to be no proper way to determine the size. */
797 __mf_register (__ctype, &MB_CUR_MAX - &__ctype[0] + 1, __MF_TYPE_STATIC, "__ctype");
798 /* __ctype_mask points at _C_masks[1]. The size can only determined
799 using nm on libc.so.1. */
800 __mf_register (__ctype_mask - 1, 1028, __MF_TYPE_STATIC, "_C_masks");
801 #endif
802 /* On modern Linux GLIBC, these are thread-specific and changeable, and are dealt
803 with in mf-hooks2.c. */
806 #ifdef PIC
807 return main (argc, argv, environ);
808 #else
809 return __real_main (argc, argv, environ);
810 #endif
815 extern void __mf_fini () DTOR;
816 void __mf_fini ()
818 TRACE ("__mf_fini\n");
819 __mfu_report ();
821 #ifndef PIC
822 /* Since we didn't populate the tree for allocations in constructors
823 before __mf_init, we cannot check destructors after __mf_fini. */
824 __mf_opts.mudflap_mode = mode_nop;
825 #endif
830 /* ------------------------------------------------------------------------ */
831 /* __mf_check */
833 void __mf_check (void *ptr, size_t sz, int type, const char *location)
835 LOCKTH ();
836 BEGIN_RECURSION_PROTECT ();
837 __mfu_check (ptr, sz, type, location);
838 END_RECURSION_PROTECT ();
839 UNLOCKTH ();
843 void __mfu_check (void *ptr, size_t sz, int type, const char *location)
845 unsigned entry_idx = __MF_CACHE_INDEX (ptr);
846 struct __mf_cache *entry = & __mf_lookup_cache [entry_idx];
847 int judgement = 0; /* 0=undecided; <0=violation; >0=okay */
848 uintptr_t ptr_low = (uintptr_t) ptr;
849 uintptr_t ptr_high = CLAMPSZ (ptr, sz);
850 struct __mf_cache old_entry = *entry;
852 if (UNLIKELY (__mf_opts.sigusr1_report))
853 __mf_sigusr1_respond ();
854 if (UNLIKELY (__mf_opts.ignore_reads && type == 0))
855 return;
857 TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n",
858 ptr, entry_idx, (unsigned long)sz,
859 (type == 0 ? "read" : "write"), location);
861 switch (__mf_opts.mudflap_mode)
863 case mode_nop:
864 /* It is tempting to poison the cache here similarly to
865 mode_populate. However that eliminates a valuable
866 distinction between these two modes. mode_nop is useful to
867 let a user count & trace every single check / registration
868 call. mode_populate is useful to let a program run fast
869 while unchecked.
871 judgement = 1;
872 break;
874 case mode_populate:
875 entry->low = ptr_low;
876 entry->high = ptr_high;
877 judgement = 1;
878 break;
880 case mode_check:
882 unsigned heuristics = 0;
884 /* Advance aging/adaptation counters. */
885 static unsigned adapt_count;
886 adapt_count ++;
887 if (UNLIKELY (__mf_opts.adapt_cache > 0 &&
888 adapt_count > __mf_opts.adapt_cache))
890 adapt_count = 0;
891 __mf_adapt_cache ();
894 /* Looping only occurs if heuristics were triggered. */
895 while (judgement == 0)
897 DECLARE (void, free, void *p);
898 __mf_object_t* ovr_obj[1];
899 unsigned obj_count;
900 __mf_object_t** all_ovr_obj = NULL;
901 __mf_object_t** dealloc_me = NULL;
902 unsigned i;
904 /* Find all overlapping objects. Be optimistic that there is just one. */
905 obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1);
906 if (UNLIKELY (obj_count > 1))
908 /* Allocate a real buffer and do the search again. */
909 DECLARE (void *, malloc, size_t c);
910 unsigned n;
911 all_ovr_obj = CALL_REAL (malloc, (sizeof (__mf_object_t *) *
912 obj_count));
913 if (all_ovr_obj == NULL) abort ();
914 n = __mf_find_objects (ptr_low, ptr_high, all_ovr_obj, obj_count);
915 assert (n == obj_count);
916 dealloc_me = all_ovr_obj;
918 else
920 all_ovr_obj = ovr_obj;
921 dealloc_me = NULL;
924 /* Update object statistics. */
925 for (i = 0; i < obj_count; i++)
927 __mf_object_t *obj = all_ovr_obj[i];
928 assert (obj != NULL);
929 if (type == __MF_CHECK_READ)
930 obj->read_count ++;
931 else
932 obj->write_count ++;
933 obj->liveness ++;
936 /* Iterate over the various objects. There are a number of special cases. */
937 for (i = 0; i < obj_count; i++)
939 __mf_object_t *obj = all_ovr_obj[i];
941 /* Any __MF_TYPE_NOACCESS hit is bad. */
942 if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS))
943 judgement = -1;
945 /* Any object with a watch flag is bad. */
946 if (UNLIKELY (obj->watching_p))
947 judgement = -2; /* trigger VIOL_WATCH */
949 /* A read from an uninitialized object is bad. */
950 if (UNLIKELY (__mf_opts.check_initialization
951 /* reading */
952 && type == __MF_CHECK_READ
953 /* not written */
954 && obj->write_count == 0
955 /* uninitialized (heap) */
956 && obj->type == __MF_TYPE_HEAP))
957 judgement = -1;
960 /* We now know that the access spans no invalid objects. */
961 if (LIKELY (judgement >= 0))
962 for (i = 0; i < obj_count; i++)
964 __mf_object_t *obj = all_ovr_obj[i];
966 /* Is this access entirely contained within this object? */
967 if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high))
969 /* Valid access. */
970 entry->low = obj->low;
971 entry->high = obj->high;
972 judgement = 1;
976 /* This access runs off the end of one valid object. That
977 could be okay, if other valid objects fill in all the
978 holes. We allow this only for HEAP and GUESS type
979 objects. Accesses to STATIC and STACK variables
980 should not be allowed to span. */
981 if (UNLIKELY ((judgement == 0) && (obj_count > 1)))
983 unsigned uncovered = 0;
984 for (i = 0; i < obj_count; i++)
986 __mf_object_t *obj = all_ovr_obj[i];
987 int j, uncovered_low_p, uncovered_high_p;
988 uintptr_t ptr_lower, ptr_higher;
990 uncovered_low_p = ptr_low < obj->low;
991 ptr_lower = CLAMPSUB (obj->low, 1);
992 uncovered_high_p = ptr_high > obj->high;
993 ptr_higher = CLAMPADD (obj->high, 1);
995 for (j = 0; j < obj_count; j++)
997 __mf_object_t *obj2 = all_ovr_obj[j];
999 if (i == j) continue;
1001 /* Filter out objects that cannot be spanned across. */
1002 if (obj2->type == __MF_TYPE_STACK
1003 || obj2->type == __MF_TYPE_STATIC)
1004 continue;
1006 /* Consider a side "covered" if obj2 includes
1007 the next byte on that side. */
1008 if (uncovered_low_p
1009 && (ptr_lower >= obj2->low && ptr_lower <= obj2->high))
1010 uncovered_low_p = 0;
1011 if (uncovered_high_p
1012 && (ptr_high >= obj2->low && ptr_higher <= obj2->high))
1013 uncovered_high_p = 0;
1016 if (uncovered_low_p || uncovered_high_p)
1017 uncovered ++;
1020 /* Success if no overlapping objects are uncovered. */
1021 if (uncovered == 0)
1022 judgement = 1;
1026 if (dealloc_me != NULL)
1027 CALL_REAL (free, dealloc_me);
1029 /* If the judgment is still unknown at this stage, loop
1030 around at most one more time. */
1031 if (judgement == 0)
1033 if (heuristics++ < 2) /* XXX parametrize this number? */
1034 judgement = __mf_heuristic_check (ptr_low, ptr_high);
1035 else
1036 judgement = -1;
1041 break;
1043 case mode_violate:
1044 judgement = -1;
1045 break;
1048 if (__mf_opts.collect_stats)
1050 __mf_count_check ++;
1052 if (LIKELY (old_entry.low != entry->low || old_entry.high != entry->high))
1053 /* && (old_entry.low != 0) && (old_entry.high != 0)) */
1054 __mf_lookup_cache_reusecount [entry_idx] ++;
1057 if (UNLIKELY (judgement < 0))
1058 __mf_violation (ptr, sz,
1059 (uintptr_t) __builtin_return_address (0), location,
1060 ((judgement == -1) ?
1061 (type == __MF_CHECK_READ ? __MF_VIOL_READ : __MF_VIOL_WRITE) :
1062 __MF_VIOL_WATCH));
1066 static __mf_object_t *
1067 __mf_insert_new_object (uintptr_t low, uintptr_t high, int type,
1068 const char *name, uintptr_t pc)
1070 DECLARE (void *, calloc, size_t c, size_t n);
1072 __mf_object_t *new_obj;
1073 new_obj = CALL_REAL (calloc, 1, sizeof(__mf_object_t));
1074 new_obj->low = low;
1075 new_obj->high = high;
1076 new_obj->type = type;
1077 new_obj->name = name;
1078 new_obj->alloc_pc = pc;
1079 #if HAVE_GETTIMEOFDAY
1080 if (__mf_opts.timestamps)
1081 gettimeofday (& new_obj->alloc_time, NULL);
1082 #endif
1083 #if LIBMUDFLAPTH
1084 new_obj->alloc_thread = pthread_self ();
1085 #endif
1087 if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I))
1088 new_obj->alloc_backtrace_size =
1089 __mf_backtrace (& new_obj->alloc_backtrace,
1090 (void *) pc, 2);
1092 __mf_link_object (new_obj);
1093 return new_obj;
1097 static void
1098 __mf_uncache_object (__mf_object_t *old_obj)
1100 /* Remove any low/high pointers for this object from the lookup cache. */
1102 /* Can it possibly exist in the cache? */
1103 if (LIKELY (old_obj->read_count + old_obj->write_count))
1105 uintptr_t low = old_obj->low;
1106 uintptr_t high = old_obj->high;
1107 struct __mf_cache *entry;
1108 unsigned i;
1109 if ((high - low) >= (__mf_lc_mask << __mf_lc_shift))
1111 /* For large objects (>= cache size - 1) check the whole cache. */
1112 entry = & __mf_lookup_cache [0];
1113 for (i = 0; i <= __mf_lc_mask; i++, entry++)
1115 /* NB: the "||" in the following test permits this code to
1116 tolerate the situation introduced by __mf_check over
1117 contiguous objects, where a cache entry spans several
1118 objects. */
1119 if (entry->low == low || entry->high == high)
1121 entry->low = MAXPTR;
1122 entry->high = MINPTR;
1126 else
1128 /* Object is now smaller then cache size. */
1129 unsigned entry_low_idx = __MF_CACHE_INDEX (low);
1130 unsigned entry_high_idx = __MF_CACHE_INDEX (high);
1131 if (entry_low_idx <= entry_high_idx)
1133 entry = & __mf_lookup_cache [entry_low_idx];
1134 for (i = entry_low_idx; i <= entry_high_idx; i++, entry++)
1136 /* NB: the "||" in the following test permits this code to
1137 tolerate the situation introduced by __mf_check over
1138 contiguous objects, where a cache entry spans several
1139 objects. */
1140 if (entry->low == low || entry->high == high)
1142 entry->low = MAXPTR;
1143 entry->high = MINPTR;
1147 else
1149 /* Object wrapped around the end of the cache. First search
1150 from low to end of cache and then from 0 to high. */
1151 entry = & __mf_lookup_cache [entry_low_idx];
1152 for (i = entry_low_idx; i <= __mf_lc_mask; i++, entry++)
1154 /* NB: the "||" in the following test permits this code to
1155 tolerate the situation introduced by __mf_check over
1156 contiguous objects, where a cache entry spans several
1157 objects. */
1158 if (entry->low == low || entry->high == high)
1160 entry->low = MAXPTR;
1161 entry->high = MINPTR;
1164 entry = & __mf_lookup_cache [0];
1165 for (i = 0; i <= entry_high_idx; i++, entry++)
1167 /* NB: the "||" in the following test permits this code to
1168 tolerate the situation introduced by __mf_check over
1169 contiguous objects, where a cache entry spans several
1170 objects. */
1171 if (entry->low == low || entry->high == high)
1173 entry->low = MAXPTR;
1174 entry->high = MINPTR;
1183 void
1184 __mf_register (void *ptr, size_t sz, int type, const char *name)
1186 LOCKTH ();
1187 BEGIN_RECURSION_PROTECT ();
1188 __mfu_register (ptr, sz, type, name);
1189 END_RECURSION_PROTECT ();
1190 UNLOCKTH ();
1194 void
1195 __mfu_register (void *ptr, size_t sz, int type, const char *name)
1197 TRACE ("register ptr=%p size=%lu type=%x name='%s'\n",
1198 ptr, (unsigned long) sz, type, name ? name : "");
1200 if (__mf_opts.collect_stats)
1202 __mf_count_register ++;
1203 __mf_total_register_size [(type < 0) ? 0 :
1204 (type > __MF_TYPE_MAX) ? 0 :
1205 type] += sz;
1208 if (UNLIKELY (__mf_opts.sigusr1_report))
1209 __mf_sigusr1_respond ();
1211 switch (__mf_opts.mudflap_mode)
1213 case mode_nop:
1214 break;
1216 case mode_violate:
1217 __mf_violation (ptr, sz, (uintptr_t) __builtin_return_address (0), NULL,
1218 __MF_VIOL_REGISTER);
1219 break;
1221 case mode_populate:
1222 /* Clear the cache. */
1223 /* XXX: why the entire cache? */
1224 /* XXX: race */
1225 memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1226 /* void slot 0 */
1227 __mf_lookup_cache[0].low = MAXPTR;
1228 break;
1230 case mode_check:
1232 __mf_object_t *ovr_objs [1];
1233 unsigned num_overlapping_objs;
1234 uintptr_t low = (uintptr_t) ptr;
1235 uintptr_t high = CLAMPSZ (ptr, sz);
1236 uintptr_t pc = (uintptr_t) __builtin_return_address (0);
1238 /* Treat unknown size indication as 1. */
1239 if (UNLIKELY (sz == 0)) sz = 1;
1241 /* Look for objects only of the same type. This will e.g. permit a registration
1242 of a STATIC overlapping with a GUESS, and a HEAP with a NOACCESS. At
1243 __mf_check time however harmful overlaps will be detected. */
1244 num_overlapping_objs = __mf_find_objects2 (low, high, ovr_objs, 1, type);
1246 /* Handle overlaps. */
1247 if (UNLIKELY (num_overlapping_objs > 0))
1249 __mf_object_t *ovr_obj = ovr_objs[0];
1251 /* Accept certain specific duplication pairs. */
1252 if (((type == __MF_TYPE_STATIC) || (type == __MF_TYPE_GUESS))
1253 && ovr_obj->low == low
1254 && ovr_obj->high == high
1255 && ovr_obj->type == type)
1257 /* Duplicate registration for static objects may come
1258 from distinct compilation units. */
1259 VERBOSE_TRACE ("harmless duplicate reg %p-%p `%s'\n",
1260 (void *) low, (void *) high,
1261 (ovr_obj->name ? ovr_obj->name : ""));
1262 break;
1265 /* Alas, a genuine violation. */
1266 else
1268 /* Two or more *real* mappings here. */
1269 __mf_violation ((void *) ptr, sz,
1270 (uintptr_t) __builtin_return_address (0), NULL,
1271 __MF_VIOL_REGISTER);
1274 else /* No overlapping objects: AOK. */
1275 __mf_insert_new_object (low, high, type, name, pc);
1277 /* We could conceivably call __mf_check() here to prime the cache,
1278 but then the read_count/write_count field is not reliable. */
1279 break;
1281 } /* end switch (__mf_opts.mudflap_mode) */
1285 void
1286 __mf_unregister (void *ptr, size_t sz, int type)
1288 LOCKTH ();
1289 BEGIN_RECURSION_PROTECT ();
1290 __mfu_unregister (ptr, sz, type);
1291 END_RECURSION_PROTECT ();
1292 UNLOCKTH ();
1296 void
1297 __mfu_unregister (void *ptr, size_t sz, int type)
1299 DECLARE (void, free, void *ptr);
1301 if (UNLIKELY (__mf_opts.sigusr1_report))
1302 __mf_sigusr1_respond ();
1304 TRACE ("unregister ptr=%p size=%lu type=%x\n", ptr, (unsigned long) sz, type);
1306 switch (__mf_opts.mudflap_mode)
1308 case mode_nop:
1309 break;
1311 case mode_violate:
1312 __mf_violation (ptr, sz,
1313 (uintptr_t) __builtin_return_address (0), NULL,
1314 __MF_VIOL_UNREGISTER);
1315 break;
1317 case mode_populate:
1318 /* Clear the cache. */
1319 /* XXX: race */
1320 memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1321 /* void slot 0 */
1322 __mf_lookup_cache[0].low = MAXPTR;
1323 break;
1325 case mode_check:
1327 __mf_object_t *old_obj = NULL;
1328 __mf_object_t *del_obj = NULL; /* Object to actually delete. */
1329 __mf_object_t *objs[1] = {NULL};
1330 unsigned num_overlapping_objs;
1332 num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
1333 CLAMPSZ (ptr, sz), objs, 1, type);
1335 /* Special case for HEAP_I - see free & realloc hook. They don't
1336 know whether the input region was HEAP or HEAP_I before
1337 unmapping it. Here we give HEAP a try in case HEAP_I
1338 failed. */
1339 if ((type == __MF_TYPE_HEAP_I) && (num_overlapping_objs == 0))
1341 num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
1342 CLAMPSZ (ptr, sz), objs, 1, __MF_TYPE_HEAP);
1345 old_obj = objs[0];
1346 if (UNLIKELY ((num_overlapping_objs != 1) /* more than one overlap */
1347 || ((sz == 0) ? 0 : (sz != (old_obj->high - old_obj->low + 1))) /* size mismatch */
1348 || ((uintptr_t) ptr != old_obj->low))) /* base mismatch */
1350 __mf_violation (ptr, sz,
1351 (uintptr_t) __builtin_return_address (0), NULL,
1352 __MF_VIOL_UNREGISTER);
1353 break;
1356 __mf_unlink_object (old_obj);
1357 __mf_uncache_object (old_obj);
1359 /* Wipe buffer contents if desired. */
1360 if ((__mf_opts.wipe_stack && old_obj->type == __MF_TYPE_STACK)
1361 || (__mf_opts.wipe_heap && (old_obj->type == __MF_TYPE_HEAP
1362 || old_obj->type == __MF_TYPE_HEAP_I)))
1364 memset ((void *) old_obj->low,
1366 (size_t) (old_obj->high - old_obj->low + 1));
1369 /* Manage the object cemetary. */
1370 if (__mf_opts.persistent_count > 0
1371 && (unsigned) old_obj->type <= __MF_TYPE_MAX_CEM)
1373 old_obj->deallocated_p = 1;
1374 old_obj->dealloc_pc = (uintptr_t) __builtin_return_address (0);
1375 #if HAVE_GETTIMEOFDAY
1376 if (__mf_opts.timestamps)
1377 gettimeofday (& old_obj->dealloc_time, NULL);
1378 #endif
1379 #ifdef LIBMUDFLAPTH
1380 old_obj->dealloc_thread = pthread_self ();
1381 #endif
1383 if (__mf_opts.backtrace > 0 && old_obj->type == __MF_TYPE_HEAP)
1384 old_obj->dealloc_backtrace_size =
1385 __mf_backtrace (& old_obj->dealloc_backtrace,
1386 NULL, 2);
1388 /* Encourage this object to be displayed again in current epoch. */
1389 old_obj->description_epoch --;
1391 /* Put this object into the cemetary. This may require this plot to
1392 be recycled, and the previous resident to be designated del_obj. */
1394 unsigned row = old_obj->type;
1395 unsigned plot = __mf_object_dead_head [row];
1397 del_obj = __mf_object_cemetary [row][plot];
1398 __mf_object_cemetary [row][plot] = old_obj;
1399 plot ++;
1400 if (plot == __mf_opts.persistent_count) plot = 0;
1401 __mf_object_dead_head [row] = plot;
1404 else
1405 del_obj = old_obj;
1407 if (__mf_opts.print_leaks)
1409 if ((old_obj->read_count + old_obj->write_count) == 0 &&
1410 (old_obj->type == __MF_TYPE_HEAP
1411 || old_obj->type == __MF_TYPE_HEAP_I))
1413 /* The problem with a warning message here is that we may not
1414 be privy to accesses to such objects that occur within
1415 uninstrumented libraries. */
1416 #if 0
1417 fprintf (stderr,
1418 "*******\n"
1419 "mudflap warning: unaccessed registered object:\n");
1420 __mf_describe_object (old_obj);
1421 #endif
1425 if (del_obj != NULL) /* May or may not equal old_obj. */
1427 if (__mf_opts.backtrace > 0)
1429 CALL_REAL(free, del_obj->alloc_backtrace);
1430 if (__mf_opts.persistent_count > 0)
1432 CALL_REAL(free, del_obj->dealloc_backtrace);
1435 CALL_REAL(free, del_obj);
1438 break;
1440 } /* end switch (__mf_opts.mudflap_mode) */
1443 if (__mf_opts.collect_stats)
1445 __mf_count_unregister ++;
1446 __mf_total_unregister_size += sz;
1452 struct tree_stats
1454 unsigned obj_count;
1455 unsigned long total_size;
1456 unsigned live_obj_count;
1457 double total_weight;
1458 double weighted_size;
1459 unsigned long weighted_address_bits [sizeof (uintptr_t) * 8][2];
1464 static int
1465 __mf_adapt_cache_fn (mfsplay_tree_node n, void *param)
1467 __mf_object_t *obj = (__mf_object_t *) n->value;
1468 struct tree_stats *s = (struct tree_stats *) param;
1470 assert (obj != NULL && s != NULL);
1472 /* Exclude never-accessed objects. */
1473 if (obj->read_count + obj->write_count)
1475 s->obj_count ++;
1476 s->total_size += (obj->high - obj->low + 1);
1478 if (obj->liveness)
1480 unsigned i;
1481 uintptr_t addr;
1483 /* VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n",
1484 (void *) obj->low, obj->liveness, obj->name); */
1486 s->live_obj_count ++;
1487 s->total_weight += (double) obj->liveness;
1488 s->weighted_size +=
1489 (double) (obj->high - obj->low + 1) *
1490 (double) obj->liveness;
1492 addr = obj->low;
1493 for (i=0; i<sizeof(uintptr_t) * 8; i++)
1495 unsigned bit = addr & 1;
1496 s->weighted_address_bits[i][bit] += obj->liveness;
1497 addr = addr >> 1;
1500 /* Age the liveness value. */
1501 obj->liveness >>= 1;
1505 return 0;
1509 static void
1510 __mf_adapt_cache ()
1512 struct tree_stats s;
1513 uintptr_t new_mask = 0;
1514 unsigned char new_shift;
1515 float cache_utilization;
1516 float max_value;
1517 static float smoothed_new_shift = -1.0;
1518 unsigned i;
1520 memset (&s, 0, sizeof (s));
1522 mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP), __mf_adapt_cache_fn, (void *) & s);
1523 mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I), __mf_adapt_cache_fn, (void *) & s);
1524 mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_STACK), __mf_adapt_cache_fn, (void *) & s);
1525 mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_STATIC), __mf_adapt_cache_fn, (void *) & s);
1526 mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_GUESS), __mf_adapt_cache_fn, (void *) & s);
1528 /* Maybe we're dealing with funny aging/adaptation parameters, or an
1529 empty tree. Just leave the cache alone in such cases, rather
1530 than risk dying by division-by-zero. */
1531 if (! (s.obj_count > 0) && (s.live_obj_count > 0) && (s.total_weight > 0.0))
1532 return;
1534 /* Guess a good value for the shift parameter by finding an address bit that is a
1535 good discriminant of lively objects. */
1536 max_value = 0.0;
1537 for (i=0; i<sizeof (uintptr_t)*8; i++)
1539 float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
1540 if (max_value < value) max_value = value;
1542 for (i=0; i<sizeof (uintptr_t)*8; i++)
1544 float shoulder_factor = 0.7; /* Include slightly less popular bits too. */
1545 float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
1546 if (value >= max_value * shoulder_factor)
1547 break;
1549 if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift;
1550 /* Converge toward this slowly to reduce flapping. */
1551 smoothed_new_shift = 0.9*smoothed_new_shift + 0.1*i;
1552 new_shift = (unsigned) (smoothed_new_shift + 0.5);
1553 assert (new_shift < sizeof (uintptr_t)*8);
1555 /* Count number of used buckets. */
1556 cache_utilization = 0.0;
1557 for (i = 0; i < (1 + __mf_lc_mask); i++)
1558 if (__mf_lookup_cache[i].low != 0 || __mf_lookup_cache[i].high != 0)
1559 cache_utilization += 1.0;
1560 cache_utilization /= (1 + __mf_lc_mask);
1562 new_mask |= 0xffff; /* XXX: force a large cache. */
1563 new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
1565 VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
1566 "util=%u%% m=%p s=%u\n",
1567 s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size,
1568 (unsigned)(cache_utilization*100.0), (void *) new_mask, new_shift);
1570 /* We should reinitialize cache if its parameters have changed. */
1571 if (new_mask != __mf_lc_mask ||
1572 new_shift != __mf_lc_shift)
1574 __mf_lc_mask = new_mask;
1575 __mf_lc_shift = new_shift;
1576 /* XXX: race */
1577 memset (__mf_lookup_cache, 0, sizeof(__mf_lookup_cache));
1578 /* void slot 0 */
1579 __mf_lookup_cache[0].low = MAXPTR;
1585 /* __mf_find_object[s] */
1587 /* Find overlapping live objecs between [low,high]. Return up to
1588 max_objs of their pointers in objs[]. Return total count of
1589 overlaps (may exceed max_objs). */
1591 unsigned
1592 __mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high,
1593 __mf_object_t **objs, unsigned max_objs, int type)
1595 unsigned count = 0;
1596 mfsplay_tree t = __mf_object_tree (type);
1597 mfsplay_tree_key k = (mfsplay_tree_key) ptr_low;
1598 int direction;
1600 mfsplay_tree_node n = mfsplay_tree_lookup (t, k);
1601 /* An exact match for base address implies a hit. */
1602 if (n != NULL)
1604 if (count < max_objs)
1605 objs[count] = (__mf_object_t *) n->value;
1606 count ++;
1609 /* Iterate left then right near this key value to find all overlapping objects. */
1610 for (direction = 0; direction < 2; direction ++)
1612 /* Reset search origin. */
1613 k = (mfsplay_tree_key) ptr_low;
1615 while (1)
1617 __mf_object_t *obj;
1619 n = (direction == 0 ? mfsplay_tree_successor (t, k) : mfsplay_tree_predecessor (t, k));
1620 if (n == NULL) break;
1621 obj = (__mf_object_t *) n->value;
1623 if (! (obj->low <= ptr_high && obj->high >= ptr_low)) /* No overlap? */
1624 break;
1626 if (count < max_objs)
1627 objs[count] = (__mf_object_t *) n->value;
1628 count ++;
1630 k = (mfsplay_tree_key) obj->low;
1634 return count;
1638 unsigned
1639 __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high,
1640 __mf_object_t **objs, unsigned max_objs)
1642 int type;
1643 unsigned count = 0;
1645 /* Search each splay tree for overlaps. */
1646 for (type = __MF_TYPE_NOACCESS; type <= __MF_TYPE_GUESS; type++)
1648 unsigned c = __mf_find_objects2 (ptr_low, ptr_high, objs, max_objs, type);
1649 if (c > max_objs)
1651 max_objs = 0;
1652 objs = NULL;
1654 else /* NB: C may equal 0 */
1656 max_objs -= c;
1657 objs += c;
1659 count += c;
1662 return count;
1667 /* __mf_link_object */
1669 static void
1670 __mf_link_object (__mf_object_t *node)
1672 mfsplay_tree t = __mf_object_tree (node->type);
1673 mfsplay_tree_insert (t, (mfsplay_tree_key) node->low, (mfsplay_tree_value) node);
1676 /* __mf_unlink_object */
1678 static void
1679 __mf_unlink_object (__mf_object_t *node)
1681 mfsplay_tree t = __mf_object_tree (node->type);
1682 mfsplay_tree_remove (t, (mfsplay_tree_key) node->low);
1685 /* __mf_find_dead_objects */
1687 /* Find overlapping dead objecs between [low,high]. Return up to
1688 max_objs of their pointers in objs[]. Return total count of
1689 overlaps (may exceed max_objs). */
1691 static unsigned
1692 __mf_find_dead_objects (uintptr_t low, uintptr_t high,
1693 __mf_object_t **objs, unsigned max_objs)
1695 if (__mf_opts.persistent_count > 0)
1697 unsigned count = 0;
1698 unsigned recollection = 0;
1699 unsigned row = 0;
1701 assert (low <= high);
1702 assert (max_objs == 0 || objs != NULL);
1704 /* Widen the search from the most recent plots in each row, looking
1705 backward in time. */
1706 recollection = 0;
1707 while (recollection < __mf_opts.persistent_count)
1709 count = 0;
1711 for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
1713 unsigned plot;
1714 unsigned i;
1716 plot = __mf_object_dead_head [row];
1717 for (i = 0; i <= recollection; i ++)
1719 __mf_object_t *obj;
1721 /* Look backward through row: it's a circular buffer. */
1722 if (plot > 0) plot --;
1723 else plot = __mf_opts.persistent_count - 1;
1725 obj = __mf_object_cemetary [row][plot];
1726 if (obj && obj->low <= high && obj->high >= low)
1728 /* Found an overlapping dead object! */
1729 if (count < max_objs)
1730 objs [count] = obj;
1731 count ++;
1736 if (count)
1737 break;
1739 /* Look farther back in time. */
1740 recollection = (recollection * 2) + 1;
1743 return count;
1744 } else {
1745 return 0;
1749 /* __mf_describe_object */
1751 static void
1752 __mf_describe_object (__mf_object_t *obj)
1754 static unsigned epoch = 0;
1755 if (obj == NULL)
1757 epoch ++;
1758 return;
1761 if (__mf_opts.abbreviate && obj->description_epoch == epoch)
1763 fprintf (stderr,
1764 "mudflap %sobject %p: name=`%s'\n",
1765 (obj->deallocated_p ? "dead " : ""),
1766 (void *) obj, (obj->name ? obj->name : ""));
1767 return;
1769 else
1770 obj->description_epoch = epoch;
1772 fprintf (stderr,
1773 "mudflap %sobject %p: name=`%s'\n"
1774 "bounds=[%p,%p] size=%lu area=%s check=%ur/%uw liveness=%u%s\n"
1775 "alloc time=%lu.%06lu pc=%p"
1776 #ifdef LIBMUDFLAPTH
1777 " thread=%u"
1778 #endif
1779 "\n",
1780 (obj->deallocated_p ? "dead " : ""),
1781 (void *) obj, (obj->name ? obj->name : ""),
1782 (void *) obj->low, (void *) obj->high,
1783 (unsigned long) (obj->high - obj->low + 1),
1784 (obj->type == __MF_TYPE_NOACCESS ? "no-access" :
1785 obj->type == __MF_TYPE_HEAP ? "heap" :
1786 obj->type == __MF_TYPE_HEAP_I ? "heap-init" :
1787 obj->type == __MF_TYPE_STACK ? "stack" :
1788 obj->type == __MF_TYPE_STATIC ? "static" :
1789 obj->type == __MF_TYPE_GUESS ? "guess" :
1790 "unknown"),
1791 obj->read_count, obj->write_count, obj->liveness,
1792 obj->watching_p ? " watching" : "",
1793 obj->alloc_time.tv_sec, obj->alloc_time.tv_usec,
1794 (void *) obj->alloc_pc
1795 #ifdef LIBMUDFLAPTH
1796 , (unsigned) obj->alloc_thread
1797 #endif
1800 if (__mf_opts.backtrace > 0)
1802 unsigned i;
1803 for (i=0; i<obj->alloc_backtrace_size; i++)
1804 fprintf (stderr, " %s\n", obj->alloc_backtrace[i]);
1807 if (__mf_opts.persistent_count > 0)
1809 if (obj->deallocated_p)
1811 fprintf (stderr, "dealloc time=%lu.%06lu pc=%p"
1812 #ifdef LIBMUDFLAPTH
1813 " thread=%u"
1814 #endif
1815 "\n",
1816 obj->dealloc_time.tv_sec, obj->dealloc_time.tv_usec,
1817 (void *) obj->dealloc_pc
1818 #ifdef LIBMUDFLAPTH
1819 , (unsigned) obj->dealloc_thread
1820 #endif
1824 if (__mf_opts.backtrace > 0)
1826 unsigned i;
1827 for (i=0; i<obj->dealloc_backtrace_size; i++)
1828 fprintf (stderr, " %s\n", obj->dealloc_backtrace[i]);
1835 static int
1836 __mf_report_leaks_fn (mfsplay_tree_node n, void *param)
1838 __mf_object_t *node = (__mf_object_t *) n->value;
1839 unsigned *count = (unsigned *) param;
1841 if (count != NULL)
1842 (*count) ++;
1844 fprintf (stderr, "Leaked object %u:\n", (*count));
1845 __mf_describe_object (node);
1847 return 0;
1851 static unsigned
1852 __mf_report_leaks ()
1854 unsigned count = 0;
1856 (void) mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP),
1857 __mf_report_leaks_fn, & count);
1858 (void) mfsplay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I),
1859 __mf_report_leaks_fn, & count);
1861 return count;
1864 /* ------------------------------------------------------------------------ */
1865 /* __mf_report */
1867 void
1868 __mf_report ()
1870 LOCKTH ();
1871 BEGIN_RECURSION_PROTECT ();
1872 __mfu_report ();
1873 END_RECURSION_PROTECT ();
1874 UNLOCKTH ();
1877 void
1878 __mfu_report ()
1880 if (__mf_opts.collect_stats)
1882 fprintf (stderr,
1883 "*******\n"
1884 "mudflap stats:\n"
1885 "calls to __mf_check: %lu\n"
1886 " __mf_register: %lu [%luB, %luB, %luB, %luB, %luB]\n"
1887 " __mf_unregister: %lu [%luB]\n"
1888 " __mf_violation: [%lu, %lu, %lu, %lu, %lu]\n",
1889 __mf_count_check,
1890 __mf_count_register,
1891 __mf_total_register_size[0], __mf_total_register_size[1],
1892 __mf_total_register_size[2], __mf_total_register_size[3],
1893 __mf_total_register_size[4], /* XXX */
1894 __mf_count_unregister, __mf_total_unregister_size,
1895 __mf_count_violation[0], __mf_count_violation[1],
1896 __mf_count_violation[2], __mf_count_violation[3],
1897 __mf_count_violation[4]);
1899 fprintf (stderr,
1900 "calls with reentrancy: %lu\n", __mf_reentrancy);
1901 #ifdef LIBMUDFLAPTH
1902 fprintf (stderr,
1903 " lock contention: %lu\n", __mf_lock_contention);
1904 #endif
1906 /* Lookup cache stats. */
1908 unsigned i;
1909 unsigned max_reuse = 0;
1910 unsigned num_used = 0;
1911 unsigned num_unused = 0;
1913 for (i = 0; i < LOOKUP_CACHE_SIZE; i++)
1915 if (__mf_lookup_cache_reusecount[i])
1916 num_used ++;
1917 else
1918 num_unused ++;
1919 if (max_reuse < __mf_lookup_cache_reusecount[i])
1920 max_reuse = __mf_lookup_cache_reusecount[i];
1922 fprintf (stderr, "lookup cache slots used: %u unused: %u peak-reuse: %u\n",
1923 num_used, num_unused, max_reuse);
1927 unsigned live_count;
1928 live_count = __mf_find_objects (MINPTR, MAXPTR, NULL, 0);
1929 fprintf (stderr, "number of live objects: %u\n", live_count);
1932 if (__mf_opts.persistent_count > 0)
1934 unsigned dead_count = 0;
1935 unsigned row, plot;
1936 for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
1937 for (plot = 0 ; plot < __mf_opts.persistent_count; plot ++)
1938 if (__mf_object_cemetary [row][plot] != 0)
1939 dead_count ++;
1940 fprintf (stderr, " zombie objects: %u\n", dead_count);
1943 if (__mf_opts.print_leaks && (__mf_opts.mudflap_mode == mode_check))
1945 unsigned l;
1946 extern void * __mf_wrap_alloca_indirect (size_t c);
1948 /* Free up any remaining alloca()'d blocks. */
1949 __mf_wrap_alloca_indirect (0);
1950 #ifdef HAVE___LIBC_FREERES
1951 if (__mf_opts.call_libc_freeres)
1953 extern void __libc_freeres (void);
1954 __libc_freeres ();
1956 #endif
1958 __mf_describe_object (NULL); /* Reset description epoch. */
1959 l = __mf_report_leaks ();
1960 fprintf (stderr, "number of leaked objects: %u\n", l);
1964 /* __mf_backtrace */
1966 size_t
1967 __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels)
1969 void ** pc_array;
1970 unsigned pc_array_size = __mf_opts.backtrace + guess_omit_levels;
1971 unsigned remaining_size;
1972 unsigned omitted_size = 0;
1973 unsigned i;
1974 DECLARE (void, free, void *ptr);
1975 DECLARE (void *, calloc, size_t c, size_t n);
1976 DECLARE (void *, malloc, size_t n);
1978 pc_array = CALL_REAL (calloc, pc_array_size, sizeof (void *) );
1979 #ifdef HAVE_BACKTRACE
1980 pc_array_size = backtrace (pc_array, pc_array_size);
1981 #else
1982 #define FETCH(n) do { if (pc_array_size >= n) { \
1983 pc_array[n] = __builtin_return_address(n); \
1984 if (pc_array[n] == 0) pc_array_size = n; } } while (0)
1986 /* Unroll some calls __builtin_return_address because this function
1987 only takes a literal integer parameter. */
1988 FETCH (0);
1989 #if 0
1990 /* XXX: __builtin_return_address sometimes crashes (!) on >0 arguments,
1991 rather than simply returning 0. :-( */
1992 FETCH (1);
1993 FETCH (2);
1994 FETCH (3);
1995 FETCH (4);
1996 FETCH (5);
1997 FETCH (6);
1998 FETCH (7);
1999 FETCH (8);
2000 if (pc_array_size > 8) pc_array_size = 9;
2001 #else
2002 if (pc_array_size > 0) pc_array_size = 1;
2003 #endif
2005 #undef FETCH
2006 #endif
2008 /* We want to trim the first few levels of the stack traceback,
2009 since they contain libmudflap wrappers and junk. If pc_array[]
2010 ends up containing a non-NULL guess_pc, then trim everything
2011 before that. Otherwise, omit the first guess_omit_levels
2012 entries. */
2014 if (guess_pc != NULL)
2015 for (i=0; i<pc_array_size; i++)
2016 if (pc_array [i] == guess_pc)
2017 omitted_size = i;
2019 if (omitted_size == 0) /* No match? */
2020 if (pc_array_size > guess_omit_levels)
2021 omitted_size = guess_omit_levels;
2023 remaining_size = pc_array_size - omitted_size;
2025 #ifdef HAVE_BACKTRACE_SYMBOLS
2026 *symbols = backtrace_symbols (pc_array + omitted_size, remaining_size);
2027 #else
2029 /* Let's construct a buffer by hand. It will have <remaining_size>
2030 char*'s at the front, pointing at individual strings immediately
2031 afterwards. */
2032 void *buffer;
2033 char *chars;
2034 char **pointers;
2035 enum { perline = 30 };
2036 buffer = CALL_REAL (malloc, remaining_size * (perline + sizeof(char *)));
2037 pointers = (char **) buffer;
2038 chars = (char *)buffer + (remaining_size * sizeof (char *));
2039 for (i = 0; i < remaining_size; i++)
2041 pointers[i] = chars;
2042 sprintf (chars, "[0x%p]", pc_array [omitted_size + i]);
2043 chars = chars + perline;
2045 *symbols = pointers;
2047 #endif
2048 CALL_REAL (free, pc_array);
2050 return remaining_size;
2053 /* ------------------------------------------------------------------------ */
2054 /* __mf_violation */
2056 void
2057 __mf_violation (void *ptr, size_t sz, uintptr_t pc,
2058 const char *location, int type)
2060 char buf [128];
2061 static unsigned violation_number;
2062 DECLARE(void, free, void *ptr);
2064 TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n",
2065 (void *) pc,
2066 (location != NULL ? location : ""), type, ptr, (unsigned long) sz);
2068 if (__mf_opts.collect_stats)
2069 __mf_count_violation [(type < 0) ? 0 :
2070 (type > __MF_VIOL_WATCH) ? 0 :
2071 type] ++;
2073 /* Print out a basic warning message. */
2074 if (__mf_opts.verbose_violations)
2076 unsigned dead_p;
2077 unsigned num_helpful = 0;
2078 struct timeval now = { 0, 0 };
2079 #if HAVE_GETTIMEOFDAY
2080 gettimeofday (& now, NULL);
2081 #endif
2083 violation_number ++;
2084 fprintf (stderr,
2085 "*******\n"
2086 "mudflap violation %u (%s): time=%lu.%06lu "
2087 "ptr=%p size=%lu\npc=%p%s%s%s\n",
2088 violation_number,
2089 ((type == __MF_VIOL_READ) ? "check/read" :
2090 (type == __MF_VIOL_WRITE) ? "check/write" :
2091 (type == __MF_VIOL_REGISTER) ? "register" :
2092 (type == __MF_VIOL_UNREGISTER) ? "unregister" :
2093 (type == __MF_VIOL_WATCH) ? "watch" : "unknown"),
2094 now.tv_sec, now.tv_usec,
2095 (void *) ptr, (unsigned long)sz, (void *) pc,
2096 (location != NULL ? " location=`" : ""),
2097 (location != NULL ? location : ""),
2098 (location != NULL ? "'" : ""));
2100 if (__mf_opts.backtrace > 0)
2102 char ** symbols;
2103 unsigned i, num;
2105 num = __mf_backtrace (& symbols, (void *) pc, 2);
2106 /* Note: backtrace_symbols calls malloc(). But since we're in
2107 __mf_violation and presumably __mf_check, it'll detect
2108 recursion, and not put the new string into the database. */
2110 for (i=0; i<num; i++)
2111 fprintf (stderr, " %s\n", symbols[i]);
2113 /* Calling free() here would trigger a violation. */
2114 CALL_REAL(free, symbols);
2118 /* Look for nearby objects. For this, we start with s_low/s_high
2119 pointing to the given area, looking for overlapping objects.
2120 If none show up, widen the search area and keep looking. */
2122 if (sz == 0) sz = 1;
2124 for (dead_p = 0; dead_p <= 1; dead_p ++) /* for dead_p in 0 1 */
2126 enum {max_objs = 3}; /* magic */
2127 __mf_object_t *objs[max_objs];
2128 unsigned num_objs = 0;
2129 uintptr_t s_low, s_high;
2130 unsigned tries = 0;
2131 unsigned i;
2133 s_low = (uintptr_t) ptr;
2134 s_high = CLAMPSZ (ptr, sz);
2136 while (tries < 16) /* magic */
2138 if (dead_p)
2139 num_objs = __mf_find_dead_objects (s_low, s_high, objs, max_objs);
2140 else
2141 num_objs = __mf_find_objects (s_low, s_high, objs, max_objs);
2143 if (num_objs) /* good enough */
2144 break;
2146 tries ++;
2148 /* XXX: tune this search strategy. It's too dependent on
2149 sz, which can vary from 1 to very big (when array index
2150 checking) numbers. */
2151 s_low = CLAMPSUB (s_low, (sz * tries * tries));
2152 s_high = CLAMPADD (s_high, (sz * tries * tries));
2155 for (i = 0; i < min (num_objs, max_objs); i++)
2157 __mf_object_t *obj = objs[i];
2158 uintptr_t low = (uintptr_t) ptr;
2159 uintptr_t high = CLAMPSZ (ptr, sz);
2160 unsigned before1 = (low < obj->low) ? obj->low - low : 0;
2161 unsigned after1 = (low > obj->high) ? low - obj->high : 0;
2162 unsigned into1 = (high >= obj->low && low <= obj->high) ? low - obj->low : 0;
2163 unsigned before2 = (high < obj->low) ? obj->low - high : 0;
2164 unsigned after2 = (high > obj->high) ? high - obj->high : 0;
2165 unsigned into2 = (high >= obj->low && low <= obj->high) ? high - obj->low : 0;
2167 fprintf (stderr, "Nearby object %u: checked region begins %uB %s and ends %uB %s\n",
2168 num_helpful + i + 1,
2169 (before1 ? before1 : after1 ? after1 : into1),
2170 (before1 ? "before" : after1 ? "after" : "into"),
2171 (before2 ? before2 : after2 ? after2 : into2),
2172 (before2 ? "before" : after2 ? "after" : "into"));
2173 __mf_describe_object (obj);
2175 num_helpful += num_objs;
2178 fprintf (stderr, "number of nearby objects: %u\n", num_helpful);
2181 /* How to finally handle this violation? */
2182 switch (__mf_opts.violation_mode)
2184 case viol_nop:
2185 break;
2186 case viol_segv:
2187 kill (getpid(), SIGSEGV);
2188 break;
2189 case viol_abort:
2190 abort ();
2191 break;
2192 case viol_gdb:
2194 snprintf (buf, 128, "gdb --pid=%u", (unsigned) getpid ());
2195 system (buf);
2196 /* XXX: should probably fork() && sleep(GDB_WAIT_PARAMETER)
2197 instead, and let the forked child execlp() gdb. That way, this
2198 subject process can be resumed under the supervision of gdb.
2199 This can't happen now, since system() only returns when gdb
2200 dies. In that case, we need to beware of starting a second
2201 concurrent gdb child upon the next violation. (But if the first
2202 gdb dies, then starting a new one is appropriate.) */
2203 break;
2207 /* ------------------------------------------------------------------------ */
2210 unsigned __mf_watch (void *ptr, size_t sz)
2212 unsigned rc;
2213 LOCKTH ();
2214 BEGIN_RECURSION_PROTECT ();
2215 rc = __mf_watch_or_not (ptr, sz, 1);
2216 END_RECURSION_PROTECT ();
2217 UNLOCKTH ();
2218 return rc;
2221 unsigned __mf_unwatch (void *ptr, size_t sz)
2223 unsigned rc;
2224 LOCKTH ();
2225 rc = __mf_watch_or_not (ptr, sz, 0);
2226 UNLOCKTH ();
2227 return rc;
2231 static unsigned
2232 __mf_watch_or_not (void *ptr, size_t sz, char flag)
2234 uintptr_t ptr_high = CLAMPSZ (ptr, sz);
2235 uintptr_t ptr_low = (uintptr_t) ptr;
2236 unsigned count = 0;
2238 TRACE ("%s ptr=%p size=%lu\n",
2239 (flag ? "watch" : "unwatch"), ptr, (unsigned long) sz);
2241 switch (__mf_opts.mudflap_mode)
2243 case mode_nop:
2244 case mode_populate:
2245 case mode_violate:
2246 count = 0;
2247 break;
2249 case mode_check:
2251 __mf_object_t **all_ovr_objs;
2252 unsigned obj_count;
2253 unsigned n;
2254 DECLARE (void *, malloc, size_t c);
2255 DECLARE (void, free, void *p);
2257 obj_count = __mf_find_objects (ptr_low, ptr_high, NULL, 0);
2258 VERBOSE_TRACE (" %u:", obj_count);
2260 all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_t *) * obj_count));
2261 if (all_ovr_objs == NULL) abort ();
2262 n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count);
2263 assert (n == obj_count);
2265 for (n = 0; n < obj_count; n ++)
2267 __mf_object_t *obj = all_ovr_objs[n];
2269 VERBOSE_TRACE (" [%p]", (void *) obj);
2270 if (obj->watching_p != flag)
2272 obj->watching_p = flag;
2273 count ++;
2275 /* Remove object from cache, to ensure next access
2276 goes through __mf_check(). */
2277 if (flag)
2278 __mf_uncache_object (obj);
2281 CALL_REAL (free, all_ovr_objs);
2283 break;
2286 return count;
2290 void
2291 __mf_sigusr1_handler (int num)
2293 __mf_sigusr1_received ++;
2296 /* Install or remove SIGUSR1 handler as necessary.
2297 Also, respond to a received pending SIGUSR1. */
2298 void
2299 __mf_sigusr1_respond ()
2301 static int handler_installed;
2303 #ifdef SIGUSR1
2304 /* Manage handler */
2305 if (__mf_opts.sigusr1_report && ! handler_installed)
2307 signal (SIGUSR1, __mf_sigusr1_handler);
2308 handler_installed = 1;
2310 else if(! __mf_opts.sigusr1_report && handler_installed)
2312 signal (SIGUSR1, SIG_DFL);
2313 handler_installed = 0;
2315 #endif
2317 /* Manage enqueued signals */
2318 if (__mf_sigusr1_received > __mf_sigusr1_handled)
2320 __mf_sigusr1_handled ++;
2321 assert (__mf_get_state () == reentrant);
2322 __mfu_report ();
2323 handler_installed = 0; /* We may need to re-enable signal; this might be a SysV library. */
2328 /* XXX: provide an alternative __assert_fail function that cannot
2329 fail due to libmudflap infinite recursion. */
2330 #ifndef NDEBUG
2332 static void
2333 write_itoa (int fd, unsigned n)
2335 enum x { bufsize = sizeof(n)*4 };
2336 char buf [bufsize];
2337 unsigned i;
2339 for (i=0; i<bufsize-1; i++)
2341 unsigned digit = n % 10;
2342 buf[bufsize-2-i] = digit + '0';
2343 n /= 10;
2344 if (n == 0)
2346 char *m = & buf [bufsize-2-i];
2347 buf[bufsize-1] = '\0';
2348 write (fd, m, strlen(m));
2349 break;
2355 void
2356 __assert_fail (const char *msg, const char *file, unsigned line, const char *func)
2358 #define write2(string) write (2, (string), strlen ((string)));
2359 write2("mf");
2360 #ifdef LIBMUDFLAPTH
2361 write2("(");
2362 write_itoa (2, (unsigned) pthread_self ());
2363 write2(")");
2364 #endif
2365 write2(": assertion failure: `");
2366 write (2, msg, strlen (msg));
2367 write2("' in ");
2368 write (2, func, strlen (func));
2369 write2(" at ");
2370 write (2, file, strlen (file));
2371 write2(":");
2372 write_itoa (2, line);
2373 write2("\n");
2374 #undef write2
2375 abort ();
2379 #endif
2383 /* Adapted splay tree code, originally from libiberty. It has been
2384 specialized for libmudflap as requested by RMS. */
2386 static void
2387 mfsplay_tree_free (void *p)
2389 DECLARE (void, free, void *p);
2390 CALL_REAL (free, p);
2393 static void *
2394 mfsplay_tree_xmalloc (size_t s)
2396 DECLARE (void *, malloc, size_t s);
2397 return CALL_REAL (malloc, s);
2401 static void mfsplay_tree_splay (mfsplay_tree, mfsplay_tree_key);
2402 static mfsplay_tree_node mfsplay_tree_splay_helper (mfsplay_tree,
2403 mfsplay_tree_key,
2404 mfsplay_tree_node *,
2405 mfsplay_tree_node *,
2406 mfsplay_tree_node *);
2409 /* Help splay SP around KEY. PARENT and GRANDPARENT are the parent
2410 and grandparent, respectively, of NODE. */
2412 static mfsplay_tree_node
2413 mfsplay_tree_splay_helper (mfsplay_tree sp,
2414 mfsplay_tree_key key,
2415 mfsplay_tree_node * node,
2416 mfsplay_tree_node * parent,
2417 mfsplay_tree_node * grandparent)
2419 mfsplay_tree_node *next;
2420 mfsplay_tree_node n;
2421 int comparison;
2423 n = *node;
2425 if (!n)
2426 return *parent;
2428 comparison = ((key > n->key) ? 1 : ((key < n->key) ? -1 : 0));
2430 if (comparison == 0)
2431 /* We've found the target. */
2432 next = 0;
2433 else if (comparison < 0)
2434 /* The target is to the left. */
2435 next = &n->left;
2436 else
2437 /* The target is to the right. */
2438 next = &n->right;
2440 if (next)
2442 /* Check whether our recursion depth is too high. Abort this search,
2443 and signal that a rebalance is required to continue. */
2444 if (sp->depth > sp->max_depth)
2446 sp->rebalance_p = 1;
2447 return n;
2450 /* Continue down the tree. */
2451 sp->depth ++;
2452 n = mfsplay_tree_splay_helper (sp, key, next, node, parent);
2453 sp->depth --;
2455 /* The recursive call will change the place to which NODE
2456 points. */
2457 if (*node != n || sp->rebalance_p)
2458 return n;
2461 if (!parent)
2462 /* NODE is the root. We are done. */
2463 return n;
2465 /* First, handle the case where there is no grandparent (i.e.,
2466 *PARENT is the root of the tree.) */
2467 if (!grandparent)
2469 if (n == (*parent)->left)
2471 *node = n->right;
2472 n->right = *parent;
2474 else
2476 *node = n->left;
2477 n->left = *parent;
2479 *parent = n;
2480 return n;
2483 /* Next handle the cases where both N and *PARENT are left children,
2484 or where both are right children. */
2485 if (n == (*parent)->left && *parent == (*grandparent)->left)
2487 mfsplay_tree_node p = *parent;
2489 (*grandparent)->left = p->right;
2490 p->right = *grandparent;
2491 p->left = n->right;
2492 n->right = p;
2493 *grandparent = n;
2494 return n;
2496 else if (n == (*parent)->right && *parent == (*grandparent)->right)
2498 mfsplay_tree_node p = *parent;
2500 (*grandparent)->right = p->left;
2501 p->left = *grandparent;
2502 p->right = n->left;
2503 n->left = p;
2504 *grandparent = n;
2505 return n;
2508 /* Finally, deal with the case where N is a left child, but *PARENT
2509 is a right child, or vice versa. */
2510 if (n == (*parent)->left)
2512 (*parent)->left = n->right;
2513 n->right = *parent;
2514 (*grandparent)->right = n->left;
2515 n->left = *grandparent;
2516 *grandparent = n;
2517 return n;
2519 else
2521 (*parent)->right = n->left;
2522 n->left = *parent;
2523 (*grandparent)->left = n->right;
2524 n->right = *grandparent;
2525 *grandparent = n;
2526 return n;
2532 static int
2533 mfsplay_tree_rebalance_helper1 (mfsplay_tree_node n, void *array_ptr)
2535 mfsplay_tree_node **p = array_ptr;
2536 *(*p) = n;
2537 (*p)++;
2538 return 0;
2542 static mfsplay_tree_node
2543 mfsplay_tree_rebalance_helper2 (mfsplay_tree_node * array, unsigned low,
2544 unsigned high)
2546 unsigned middle = low + (high - low) / 2;
2547 mfsplay_tree_node n = array[middle];
2549 /* Note that since we're producing a balanced binary tree, it is not a problem
2550 that this function is recursive. */
2551 if (low + 1 <= middle)
2552 n->left = mfsplay_tree_rebalance_helper2 (array, low, middle - 1);
2553 else
2554 n->left = NULL;
2556 if (middle + 1 <= high)
2557 n->right = mfsplay_tree_rebalance_helper2 (array, middle + 1, high);
2558 else
2559 n->right = NULL;
2561 return n;
2565 /* Rebalance the entire tree. Do this by copying all the node
2566 pointers into an array, then cleverly re-linking them. */
2567 static void
2568 mfsplay_tree_rebalance (mfsplay_tree sp)
2570 mfsplay_tree_node *all_nodes, *all_nodes_1;
2572 if (sp->num_keys <= 2)
2573 return;
2575 all_nodes = mfsplay_tree_xmalloc (sizeof (mfsplay_tree_node) * sp->num_keys);
2577 /* Traverse all nodes to copy their addresses into this array. */
2578 all_nodes_1 = all_nodes;
2579 mfsplay_tree_foreach (sp, mfsplay_tree_rebalance_helper1,
2580 (void *) &all_nodes_1);
2582 /* Relink all the nodes. */
2583 sp->root = mfsplay_tree_rebalance_helper2 (all_nodes, 0, sp->num_keys - 1);
2585 mfsplay_tree_free (all_nodes);
2589 /* Splay SP around KEY. */
2590 static void
2591 mfsplay_tree_splay (mfsplay_tree sp, mfsplay_tree_key key)
2593 if (sp->root == 0)
2594 return;
2596 /* If we just splayed the tree with the same key, do nothing. */
2597 if (sp->last_splayed_key_p &&
2598 (sp->last_splayed_key == key))
2599 return;
2601 /* Compute a maximum recursion depth for a splay tree with NUM nodes.
2602 The idea is to limit excessive stack usage if we're facing
2603 degenerate access patterns. Unfortunately such patterns can occur
2604 e.g. during static initialization, where many static objects might
2605 be registered in increasing address sequence, or during a case where
2606 large tree-like heap data structures are allocated quickly.
2608 On x86, this corresponds to roughly 200K of stack usage.
2609 XXX: For libmudflapth, this could be a function of __mf_opts.thread_stack. */
2610 sp->max_depth = 2500;
2611 sp->rebalance_p = sp->depth = 0;
2613 mfsplay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
2614 if (sp->rebalance_p)
2616 mfsplay_tree_rebalance (sp);
2618 sp->rebalance_p = sp->depth = 0;
2619 mfsplay_tree_splay_helper (sp, key, &sp->root, NULL, NULL);
2621 if (sp->rebalance_p)
2622 abort ();
2626 /* Cache this splay key. */
2627 sp->last_splayed_key = key;
2628 sp->last_splayed_key_p = 1;
2633 /* Allocate a new splay tree. */
2634 static mfsplay_tree
2635 mfsplay_tree_new ()
2637 mfsplay_tree sp = mfsplay_tree_xmalloc (sizeof (struct mfsplay_tree_s));
2638 sp->root = NULL;
2639 sp->last_splayed_key_p = 0;
2640 sp->num_keys = 0;
2642 return sp;
2647 /* Insert a new node (associating KEY with DATA) into SP. If a
2648 previous node with the indicated KEY exists, its data is replaced
2649 with the new value. Returns the new node. */
2650 static mfsplay_tree_node
2651 mfsplay_tree_insert (mfsplay_tree sp, mfsplay_tree_key key, mfsplay_tree_value value)
2653 int comparison = 0;
2655 mfsplay_tree_splay (sp, key);
2657 if (sp->root)
2658 comparison = ((sp->root->key > key) ? 1 :
2659 ((sp->root->key < key) ? -1 : 0));
2661 if (sp->root && comparison == 0)
2663 /* If the root of the tree already has the indicated KEY, just
2664 replace the value with VALUE. */
2665 sp->root->value = value;
2667 else
2669 /* Create a new node, and insert it at the root. */
2670 mfsplay_tree_node node;
2672 node = mfsplay_tree_xmalloc (sizeof (struct mfsplay_tree_node_s));
2673 node->key = key;
2674 node->value = value;
2675 sp->num_keys++;
2676 if (!sp->root)
2677 node->left = node->right = 0;
2678 else if (comparison < 0)
2680 node->left = sp->root;
2681 node->right = node->left->right;
2682 node->left->right = 0;
2684 else
2686 node->right = sp->root;
2687 node->left = node->right->left;
2688 node->right->left = 0;
2691 sp->root = node;
2692 sp->last_splayed_key_p = 0;
2695 return sp->root;
2698 /* Remove KEY from SP. It is not an error if it did not exist. */
2700 static void
2701 mfsplay_tree_remove (mfsplay_tree sp, mfsplay_tree_key key)
2703 mfsplay_tree_splay (sp, key);
2704 sp->last_splayed_key_p = 0;
2705 if (sp->root && (sp->root->key == key))
2707 mfsplay_tree_node left, right;
2708 left = sp->root->left;
2709 right = sp->root->right;
2710 /* Delete the root node itself. */
2711 mfsplay_tree_free (sp->root);
2712 sp->num_keys--;
2713 /* One of the children is now the root. Doesn't matter much
2714 which, so long as we preserve the properties of the tree. */
2715 if (left)
2717 sp->root = left;
2718 /* If there was a right child as well, hang it off the
2719 right-most leaf of the left child. */
2720 if (right)
2722 while (left->right)
2723 left = left->right;
2724 left->right = right;
2727 else
2728 sp->root = right;
2732 /* Lookup KEY in SP, returning VALUE if present, and NULL
2733 otherwise. */
2735 static mfsplay_tree_node
2736 mfsplay_tree_lookup (mfsplay_tree sp, mfsplay_tree_key key)
2738 mfsplay_tree_splay (sp, key);
2739 if (sp->root && (sp->root->key == key))
2740 return sp->root;
2741 else
2742 return 0;
2746 /* Return the immediate predecessor KEY, or NULL if there is no
2747 predecessor. KEY need not be present in the tree. */
2749 static mfsplay_tree_node
2750 mfsplay_tree_predecessor (mfsplay_tree sp, mfsplay_tree_key key)
2752 int comparison;
2753 mfsplay_tree_node node;
2754 /* If the tree is empty, there is certainly no predecessor. */
2755 if (!sp->root)
2756 return NULL;
2757 /* Splay the tree around KEY. That will leave either the KEY
2758 itself, its predecessor, or its successor at the root. */
2759 mfsplay_tree_splay (sp, key);
2760 comparison = ((sp->root->key > key) ? 1 :
2761 ((sp->root->key < key) ? -1 : 0));
2763 /* If the predecessor is at the root, just return it. */
2764 if (comparison < 0)
2765 return sp->root;
2766 /* Otherwise, find the rightmost element of the left subtree. */
2767 node = sp->root->left;
2768 if (node)
2769 while (node->right)
2770 node = node->right;
2771 return node;
2774 /* Return the immediate successor KEY, or NULL if there is no
2775 successor. KEY need not be present in the tree. */
2777 static mfsplay_tree_node
2778 mfsplay_tree_successor (mfsplay_tree sp, mfsplay_tree_key key)
2780 int comparison;
2781 mfsplay_tree_node node;
2782 /* If the tree is empty, there is certainly no successor. */
2783 if (!sp->root)
2784 return NULL;
2785 /* Splay the tree around KEY. That will leave either the KEY
2786 itself, its predecessor, or its successor at the root. */
2787 mfsplay_tree_splay (sp, key);
2788 comparison = ((sp->root->key > key) ? 1 :
2789 ((sp->root->key < key) ? -1 : 0));
2790 /* If the successor is at the root, just return it. */
2791 if (comparison > 0)
2792 return sp->root;
2793 /* Otherwise, find the leftmost element of the right subtree. */
2794 node = sp->root->right;
2795 if (node)
2796 while (node->left)
2797 node = node->left;
2798 return node;
2801 /* Call FN, passing it the DATA, for every node in SP, following an
2802 in-order traversal. If FN every returns a non-zero value, the
2803 iteration ceases immediately, and the value is returned.
2804 Otherwise, this function returns 0.
2806 This function simulates recursion using dynamically allocated
2807 arrays, since it may be called from mfsplay_tree_rebalance(), which
2808 in turn means that the tree is already uncomfortably deep for stack
2809 space limits. */
2810 static int
2811 mfsplay_tree_foreach (mfsplay_tree st, mfsplay_tree_foreach_fn fn, void *data)
2813 mfsplay_tree_node *stack1;
2814 char *stack2;
2815 unsigned sp;
2816 int val = 0;
2817 enum s { s_left, s_here, s_right, s_up };
2819 if (st->root == NULL) /* => num_keys == 0 */
2820 return 0;
2822 stack1 = mfsplay_tree_xmalloc (sizeof (mfsplay_tree_node) * st->num_keys);
2823 stack2 = mfsplay_tree_xmalloc (sizeof (char) * st->num_keys);
2825 sp = 0;
2826 stack1 [sp] = st->root;
2827 stack2 [sp] = s_left;
2829 while (1)
2831 mfsplay_tree_node n;
2832 enum s s;
2834 n = stack1 [sp];
2835 s = stack2 [sp];
2837 /* Handle each of the four possible states separately. */
2839 /* 1: We're here to traverse the left subtree (if any). */
2840 if (s == s_left)
2842 stack2 [sp] = s_here;
2843 if (n->left != NULL)
2845 sp ++;
2846 stack1 [sp] = n->left;
2847 stack2 [sp] = s_left;
2851 /* 2: We're here to traverse this node. */
2852 else if (s == s_here)
2854 stack2 [sp] = s_right;
2855 val = (*fn) (n, data);
2856 if (val) break;
2859 /* 3: We're here to traverse the right subtree (if any). */
2860 else if (s == s_right)
2862 stack2 [sp] = s_up;
2863 if (n->right != NULL)
2865 sp ++;
2866 stack1 [sp] = n->right;
2867 stack2 [sp] = s_left;
2871 /* 4: We're here after both subtrees (if any) have been traversed. */
2872 else if (s == s_up)
2874 /* Pop the stack. */
2875 if (sp == 0) break; /* Popping off the root note: we're finished! */
2876 sp --;
2879 else
2880 abort ();
2883 mfsplay_tree_free (stack1);
2884 mfsplay_tree_free (stack2);
2885 return val;