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
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
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/>. */
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__)
35 #endif /* Some BSDs break <sys/socket.h> if this is defined. */
39 #define __EXTENSIONS__
41 #define _LARGE_FILE_API
42 #define _XOPEN_SOURCE_EXTENDED 1
46 #include <sys/types.h>
50 #ifdef HAVE_EXECINFO_H
60 #include <sys/types.h>
65 #include "mf-runtime.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
86 mfsplay_tree_value value
;
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. */
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
101 mfsplay_tree_key last_splayed_key
;
102 int last_splayed_key_p
;
107 /* Traversal recursion control flags. */
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 /* ------------------------------------------------------------------------ */
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. */
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); \
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;
175 #if defined(HAVE_TLS) && !defined(USE_EMUTLS)
176 __thread
enum __mf_state_enum __mf_state_1
= reentrant
;
179 enum __mf_state_enum __mf_state_1
= reentrant
;
183 pthread_mutex_t __mf_biglock
=
184 #ifdef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
185 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
;
187 PTHREAD_MUTEX_INITIALIZER
;
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. */
195 #ifdef _POSIX_THREADS
196 #pragma weak pthread_join
198 #define pthread_join NULL
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
;
217 /* not static */ unsigned long __mf_lock_contention
;
221 /* ------------------------------------------------------------------------ */
222 /* mode-check-related globals. */
224 typedef struct __mf_object
226 uintptr_t low
, high
; /* __mf_register parameters */
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. */
236 struct timeval alloc_time
;
237 char **alloc_backtrace
;
238 size_t alloc_backtrace_size
;
240 pthread_t alloc_thread
;
244 uintptr_t dealloc_pc
;
245 struct timeval dealloc_time
;
246 char **dealloc_backtrace
;
247 size_t dealloc_backtrace_size
;
249 pthread_t dealloc_thread
;
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 */
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;
301 __mf_opts
.heur_std_data
= 1;
303 __mf_opts
.thread_stack
= 0;
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
330 "mudflaps do nothing",
331 set_option
, (unsigned)mode_nop
, (unsigned *)&__mf_opts
.mudflap_mode
},
333 "mudflaps populate object tree",
334 set_option
, (unsigned)mode_populate
, (unsigned *)&__mf_opts
.mudflap_mode
},
336 "mudflaps check for memory violations",
337 set_option
, (unsigned)mode_check
, (unsigned *)&__mf_opts
.mudflap_mode
},
339 "mudflaps always cause violations (diagnostic)",
340 set_option
, (unsigned)mode_violate
, (unsigned *)&__mf_opts
.mudflap_mode
},
343 "violations do not change program execution",
344 set_option
, (unsigned)viol_nop
, (unsigned *)&__mf_opts
.violation_mode
},
346 "violations cause a call to abort()",
347 set_option
, (unsigned)viol_abort
, (unsigned *)&__mf_opts
.violation_mode
},
349 "violations are promoted to SIGSEGV signals",
350 set_option
, (unsigned)viol_segv
, (unsigned *)&__mf_opts
.violation_mode
},
352 "violations fork a gdb process attached to current program",
353 set_option
, (unsigned)viol_gdb
, (unsigned *)&__mf_opts
.violation_mode
},
355 "trace calls to mudflap runtime library",
356 set_option
, 1, &__mf_opts
.trace_mf_calls
},
358 "trace internal events within mudflap runtime library",
359 set_option
, 1, &__mf_opts
.verbose_trace
},
361 "collect statistics on mudflap's operation",
362 set_option
, 1, &__mf_opts
.collect_stats
},
365 "print report upon SIGUSR1",
366 set_option
, 1, &__mf_opts
.sigusr1_report
},
368 {"internal-checking",
369 "perform more expensive internal checking",
370 set_option
, 1, &__mf_opts
.internal_checking
},
372 "print any memory leaks at program shutdown",
373 set_option
, 1, &__mf_opts
.print_leaks
},
374 #ifdef HAVE___LIBC_FREERES
376 "call glibc __libc_freeres at shutdown for better leak data",
377 set_option
, 1, &__mf_opts
.call_libc_freeres
},
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
},
386 "abbreviate repetitive listings",
387 set_option
, 1, &__mf_opts
.abbreviate
},
389 "track object lifetime timestamps",
390 set_option
, 1, &__mf_opts
.timestamps
},
392 "ignore read accesses - assume okay",
393 set_option
, 1, &__mf_opts
.ignore_reads
},
395 "wipe stack objects at unwind",
396 set_option
, 1, &__mf_opts
.wipe_stack
},
398 "wipe heap objects at free",
399 set_option
, 1, &__mf_opts
.wipe_heap
},
401 "support /proc/self/map heuristics",
402 set_option
, 1, &__mf_opts
.heur_proc_map
},
404 "enable a simple upper stack bound heuristic",
405 set_option
, 1, &__mf_opts
.heur_stack_bound
},
407 "support _start.._end heuristics",
408 set_option
, 1, &__mf_opts
.heur_start_end
},
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
},
416 "keep a history of N unregistered regions",
417 read_integer_option
, 0, &__mf_opts
.persistent_count
},
419 "surround allocations with crumple zones of N bytes",
420 read_integer_option
, 0, &__mf_opts
.crumple_zone
},
421 /* XXX: not type-safe.
423 "set lookup cache size mask to N (2**M - 1)",
424 read_integer_option, 0, (int *)(&__mf_lc_mask)},
426 "set lookup cache pointer shift",
427 read_integer_option, 0, (int *)(&__mf_lc_shift)},
430 "adapt mask/shift parameters after N cache misses",
431 read_integer_option
, 1, &__mf_opts
.adapt_cache
},
433 "keep an N-level stack trace of each call context",
434 read_integer_option
, 0, &__mf_opts
.backtrace
},
437 "override thread stacks allocation: N kB",
438 read_integer_option
, 0, &__mf_opts
.thread_stack
},
440 {0, 0, set_option
, 0, NULL
}
446 struct mudoption
*opt
;
449 "This is a %s%sGCC \"mudflap\" memory-checked binary.\n"
450 "Mudflap is Copyright (C) 2002-2013 Free Software Foundation, Inc.\n"
452 "Unless setuid, a program's mudflap options be set by an environment variable:\n"
454 "$ export MUDFLAP_OPTIONS='<options>'\n"
455 "$ <mudflapped_program>\n"
457 "where <options> is a space-separated list of \n"
458 "any of the following options. Use `-no-OPTION' to disable options.\n"
461 (pthread_join
? "multi-threaded " : "single-threaded "),
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
);
481 fprintf (stderr
, "-%-23.23s %s", opt
->name
, opt
->description
);
483 fprintf (stderr
, " [active]\n");
485 fprintf (stderr
, "\n");
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
);
497 fprintf (stderr
, "\n");
502 __mf_set_options (const char *optstr
)
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 ();
518 __mfu_set_options (const char *optstr
)
520 struct mudoption
*opts
= 0;
524 const char *saved_optstr
= optstr
;
526 /* XXX: bounds-check for optstr! */
543 if (*optstr
== '?' ||
544 strncmp (optstr
, "help", 4) == 0)
546 /* Caller will print help and exit. */
550 if (strncmp (optstr
, "no-", 3) == 0)
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
);
568 *(opts
->target
) = opts
->value
;
570 case read_integer_option
:
571 if (! negate
&& (*optstr
== '=' && *(optstr
+1)))
574 tmp
= strtol (optstr
, &nxt
, 10);
575 if ((optstr
!= nxt
) && (tmp
!= LONG_MAX
))
578 *(opts
->target
) = (int)tmp
;
592 "warning: unrecognized string '%s' in mudflap options\n",
594 optstr
+= strlen (optstr
);
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. */
606 memset (__mf_lookup_cache
, 0, sizeof(__mf_lookup_cache
));
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 ();
622 __mf_resolve_single_dynamic (struct __mf_dynamic_entry
*e
)
627 if (e
->pointer
) return;
630 if (e
->version
!= NULL
&& e
->version
[0] != '\0') /* non-null/empty */
631 e
->pointer
= dlvsym (RTLD_NEXT
, e
->name
, e
->version
);
634 e
->pointer
= dlsym (RTLD_NEXT
, e
->name
);
640 fprintf (stderr
, "mf: error in dlsym(\"%s\"): %s\n",
646 fprintf (stderr
, "mf: dlsym(\"%s\") = NULL\n", e
->name
);
653 __mf_resolve_dynamics ()
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
},
669 {NULL
, "mmap64", NULL
},
671 {NULL
, "munmap", NULL
},
672 {NULL
, "realloc", NULL
},
673 {NULL
, "DUMMY", NULL
}, /* dyn_INITRESOLVE */
675 {NULL
, "pthread_create", PTHREAD_CREATE_VERSION
},
676 {NULL
, "pthread_join", NULL
},
677 {NULL
, "pthread_exit", NULL
}
685 /* ------------------------------------------------------------------------ */
687 /* Lookup & manage automatic initialization of the five or so splay trees. */
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 ();
704 /* Return if initialization has already been done. */
705 if (LIKELY (__mf_starting_p
== 0))
708 #if defined(__FreeBSD__) && defined(LIBMUDFLAPTH)
712 #endif /* Prime mutex which calls calloc upon first lock to avoid deadlock. */
714 /* This initial bootstrap phase requires that __mf_starting_p = 1. */
716 __mf_resolve_dynamics ();
720 __mf_set_state (active
);
722 __mf_set_default_options ();
724 if (getuid () == geteuid () && getgid () == getegid ()) /* PR41433, not setuid */
725 ov
= getenv ("MUDFLAP_OPTIONS");
728 int rc
= __mfu_set_options (ov
);
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
;
759 extern int __real_main ();
760 static int been_here
= 0;
762 if (__mf_opts
.heur_std_data
&& ! been_here
)
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");
776 char *e
= environ
[i
];
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");
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");
802 /* On modern Linux GLIBC, these are thread-specific and changeable, and are dealt
803 with in mf-hooks2.c. */
807 return main (argc
, argv
, environ
);
809 return __real_main (argc
, argv
, environ
);
815 extern void __mf_fini () DTOR
;
818 TRACE ("__mf_fini\n");
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
;
830 /* ------------------------------------------------------------------------ */
833 void __mf_check (void *ptr
, size_t sz
, int type
, const char *location
)
836 BEGIN_RECURSION_PROTECT ();
837 __mfu_check (ptr
, sz
, type
, location
);
838 END_RECURSION_PROTECT ();
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))
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
)
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
875 entry
->low
= ptr_low
;
876 entry
->high
= ptr_high
;
882 unsigned heuristics
= 0;
884 /* Advance aging/adaptation counters. */
885 static unsigned adapt_count
;
887 if (UNLIKELY (__mf_opts
.adapt_cache
> 0 &&
888 adapt_count
> __mf_opts
.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];
900 __mf_object_t
** all_ovr_obj
= NULL
;
901 __mf_object_t
** dealloc_me
= NULL
;
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
);
911 all_ovr_obj
= CALL_REAL (malloc
, (sizeof (__mf_object_t
*) *
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
;
920 all_ovr_obj
= ovr_obj
;
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
)
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
))
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
952 && type
== __MF_CHECK_READ
954 && obj
->write_count
== 0
955 /* uninitialized (heap) */
956 && obj
->type
== __MF_TYPE_HEAP
))
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
))
970 entry
->low
= obj
->low
;
971 entry
->high
= obj
->high
;
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
)
1006 /* Consider a side "covered" if obj2 includes
1007 the next byte on that side. */
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
)
1020 /* Success if no overlapping objects are uncovered. */
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. */
1033 if (heuristics
++ < 2) /* XXX parametrize this number? */
1034 judgement
= __mf_heuristic_check (ptr_low
, ptr_high
);
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
) :
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
));
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
);
1084 new_obj
->alloc_thread
= pthread_self ();
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
,
1092 __mf_link_object (new_obj
);
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
;
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
1119 if (entry
->low
== low
|| entry
->high
== high
)
1121 entry
->low
= MAXPTR
;
1122 entry
->high
= MINPTR
;
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
1140 if (entry
->low
== low
|| entry
->high
== high
)
1142 entry
->low
= MAXPTR
;
1143 entry
->high
= MINPTR
;
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
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
1171 if (entry
->low
== low
|| entry
->high
== high
)
1173 entry
->low
= MAXPTR
;
1174 entry
->high
= MINPTR
;
1184 __mf_register (void *ptr
, size_t sz
, int type
, const char *name
)
1187 BEGIN_RECURSION_PROTECT ();
1188 __mfu_register (ptr
, sz
, type
, name
);
1189 END_RECURSION_PROTECT ();
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 :
1208 if (UNLIKELY (__mf_opts
.sigusr1_report
))
1209 __mf_sigusr1_respond ();
1211 switch (__mf_opts
.mudflap_mode
)
1217 __mf_violation (ptr
, sz
, (uintptr_t) __builtin_return_address (0), NULL
,
1218 __MF_VIOL_REGISTER
);
1222 /* Clear the cache. */
1223 /* XXX: why the entire cache? */
1225 memset (__mf_lookup_cache
, 0, sizeof(__mf_lookup_cache
));
1227 __mf_lookup_cache
[0].low
= MAXPTR
;
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
: ""));
1265 /* Alas, a genuine violation. */
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. */
1281 } /* end switch (__mf_opts.mudflap_mode) */
1286 __mf_unregister (void *ptr
, size_t sz
, int type
)
1289 BEGIN_RECURSION_PROTECT ();
1290 __mfu_unregister (ptr
, sz
, type
);
1291 END_RECURSION_PROTECT ();
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
)
1312 __mf_violation (ptr
, sz
,
1313 (uintptr_t) __builtin_return_address (0), NULL
,
1314 __MF_VIOL_UNREGISTER
);
1318 /* Clear the cache. */
1320 memset (__mf_lookup_cache
, 0, sizeof(__mf_lookup_cache
));
1322 __mf_lookup_cache
[0].low
= MAXPTR
;
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
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
);
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
);
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
);
1380 old_obj
->dealloc_thread
= pthread_self ();
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
,
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
;
1400 if (plot
== __mf_opts
.persistent_count
) plot
= 0;
1401 __mf_object_dead_head
[row
] = plot
;
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. */
1419 "mudflap warning: unaccessed registered object:\n");
1420 __mf_describe_object (old_obj
);
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
);
1440 } /* end switch (__mf_opts.mudflap_mode) */
1443 if (__mf_opts
.collect_stats
)
1445 __mf_count_unregister
++;
1446 __mf_total_unregister_size
+= sz
;
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];
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
)
1476 s
->total_size
+= (obj
->high
- obj
->low
+ 1);
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
;
1489 (double) (obj
->high
- obj
->low
+ 1) *
1490 (double) obj
->liveness
;
1493 for (i
=0; i
<sizeof(uintptr_t) * 8; i
++)
1495 unsigned bit
= addr
& 1;
1496 s
->weighted_address_bits
[i
][bit
] += obj
->liveness
;
1500 /* Age the liveness value. */
1501 obj
->liveness
>>= 1;
1512 struct tree_stats s
;
1513 uintptr_t new_mask
= 0;
1514 unsigned char new_shift
;
1515 float cache_utilization
;
1517 static float smoothed_new_shift
= -1.0;
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))
1534 /* Guess a good value for the shift parameter by finding an address bit that is a
1535 good discriminant of lively objects. */
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
)
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
;
1577 memset (__mf_lookup_cache
, 0, sizeof(__mf_lookup_cache
));
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). */
1592 __mf_find_objects2 (uintptr_t ptr_low
, uintptr_t ptr_high
,
1593 __mf_object_t
**objs
, unsigned max_objs
, int type
)
1596 mfsplay_tree t
= __mf_object_tree (type
);
1597 mfsplay_tree_key k
= (mfsplay_tree_key
) ptr_low
;
1600 mfsplay_tree_node n
= mfsplay_tree_lookup (t
, k
);
1601 /* An exact match for base address implies a hit. */
1604 if (count
< max_objs
)
1605 objs
[count
] = (__mf_object_t
*) n
->value
;
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
;
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? */
1626 if (count
< max_objs
)
1627 objs
[count
] = (__mf_object_t
*) n
->value
;
1630 k
= (mfsplay_tree_key
) obj
->low
;
1639 __mf_find_objects (uintptr_t ptr_low
, uintptr_t ptr_high
,
1640 __mf_object_t
**objs
, unsigned max_objs
)
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
);
1654 else /* NB: C may equal 0 */
1667 /* __mf_link_object */
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 */
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). */
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)
1698 unsigned recollection
= 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. */
1707 while (recollection
< __mf_opts
.persistent_count
)
1711 for (row
= 0; row
<= __MF_TYPE_MAX_CEM
; row
++)
1716 plot
= __mf_object_dead_head
[row
];
1717 for (i
= 0; i
<= recollection
; i
++)
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
)
1739 /* Look farther back in time. */
1740 recollection
= (recollection
* 2) + 1;
1749 /* __mf_describe_object */
1752 __mf_describe_object (__mf_object_t
*obj
)
1754 static unsigned epoch
= 0;
1761 if (__mf_opts
.abbreviate
&& obj
->description_epoch
== epoch
)
1764 "mudflap %sobject %p: name=`%s'\n",
1765 (obj
->deallocated_p
? "dead " : ""),
1766 (void *) obj
, (obj
->name
? obj
->name
: ""));
1770 obj
->description_epoch
= epoch
;
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"
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" :
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
1796 , (unsigned) obj
->alloc_thread
1800 if (__mf_opts
.backtrace
> 0)
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"
1816 obj
->dealloc_time
.tv_sec
, obj
->dealloc_time
.tv_usec
,
1817 (void *) obj
->dealloc_pc
1819 , (unsigned) obj
->dealloc_thread
1824 if (__mf_opts
.backtrace
> 0)
1827 for (i
=0; i
<obj
->dealloc_backtrace_size
; i
++)
1828 fprintf (stderr
, " %s\n", obj
->dealloc_backtrace
[i
]);
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
;
1844 fprintf (stderr
, "Leaked object %u:\n", (*count
));
1845 __mf_describe_object (node
);
1852 __mf_report_leaks ()
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
);
1864 /* ------------------------------------------------------------------------ */
1871 BEGIN_RECURSION_PROTECT ();
1873 END_RECURSION_PROTECT ();
1880 if (__mf_opts
.collect_stats
)
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",
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]);
1900 "calls with reentrancy: %lu\n", __mf_reentrancy
);
1903 " lock contention: %lu\n", __mf_lock_contention
);
1906 /* Lookup cache stats. */
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
])
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;
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)
1940 fprintf (stderr
, " zombie objects: %u\n", dead_count
);
1943 if (__mf_opts
.print_leaks
&& (__mf_opts
.mudflap_mode
== mode_check
))
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);
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 */
1967 __mf_backtrace (char ***symbols
, void *guess_pc
, unsigned guess_omit_levels
)
1970 unsigned pc_array_size
= __mf_opts
.backtrace
+ guess_omit_levels
;
1971 unsigned remaining_size
;
1972 unsigned omitted_size
= 0;
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
);
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. */
1990 /* XXX: __builtin_return_address sometimes crashes (!) on >0 arguments,
1991 rather than simply returning 0. :-( */
2000 if (pc_array_size
> 8) pc_array_size
= 9;
2002 if (pc_array_size
> 0) pc_array_size
= 1;
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
2014 if (guess_pc
!= NULL
)
2015 for (i
=0; i
<pc_array_size
; i
++)
2016 if (pc_array
[i
] == guess_pc
)
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
);
2029 /* Let's construct a buffer by hand. It will have <remaining_size>
2030 char*'s at the front, pointing at individual strings immediately
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
;
2048 CALL_REAL (free
, pc_array
);
2050 return remaining_size
;
2053 /* ------------------------------------------------------------------------ */
2054 /* __mf_violation */
2057 __mf_violation (void *ptr
, size_t sz
, uintptr_t pc
,
2058 const char *location
, int type
)
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",
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 :
2073 /* Print out a basic warning message. */
2074 if (__mf_opts
.verbose_violations
)
2077 unsigned num_helpful
= 0;
2078 struct timeval now
= { 0, 0 };
2079 #if HAVE_GETTIMEOFDAY
2080 gettimeofday (& now
, NULL
);
2083 violation_number
++;
2086 "mudflap violation %u (%s): time=%lu.%06lu "
2087 "ptr=%p size=%lu\npc=%p%s%s%s\n",
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)
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
;
2133 s_low
= (uintptr_t) ptr
;
2134 s_high
= CLAMPSZ (ptr
, sz
);
2136 while (tries
< 16) /* magic */
2139 num_objs
= __mf_find_dead_objects (s_low
, s_high
, objs
, max_objs
);
2141 num_objs
= __mf_find_objects (s_low
, s_high
, objs
, max_objs
);
2143 if (num_objs
) /* good enough */
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
)
2187 kill (getpid(), SIGSEGV
);
2194 snprintf (buf
, 128, "gdb --pid=%u", (unsigned) getpid ());
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.) */
2207 /* ------------------------------------------------------------------------ */
2210 unsigned __mf_watch (void *ptr
, size_t sz
)
2214 BEGIN_RECURSION_PROTECT ();
2215 rc
= __mf_watch_or_not (ptr
, sz
, 1);
2216 END_RECURSION_PROTECT ();
2221 unsigned __mf_unwatch (void *ptr
, size_t sz
)
2225 rc
= __mf_watch_or_not (ptr
, sz
, 0);
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
;
2238 TRACE ("%s ptr=%p size=%lu\n",
2239 (flag
? "watch" : "unwatch"), ptr
, (unsigned long) sz
);
2241 switch (__mf_opts
.mudflap_mode
)
2251 __mf_object_t
**all_ovr_objs
;
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
;
2275 /* Remove object from cache, to ensure next access
2276 goes through __mf_check(). */
2278 __mf_uncache_object (obj
);
2281 CALL_REAL (free
, all_ovr_objs
);
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. */
2299 __mf_sigusr1_respond ()
2301 static int handler_installed
;
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;
2317 /* Manage enqueued signals */
2318 if (__mf_sigusr1_received
> __mf_sigusr1_handled
)
2320 __mf_sigusr1_handled
++;
2321 assert (__mf_get_state () == reentrant
);
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. */
2333 write_itoa (int fd
, unsigned n
)
2335 enum x
{ bufsize
= sizeof(n
)*4 };
2339 for (i
=0; i
<bufsize
-1; i
++)
2341 unsigned digit
= n
% 10;
2342 buf
[bufsize
-2-i
] = digit
+ '0';
2346 char *m
= & buf
[bufsize
-2-i
];
2347 buf
[bufsize
-1] = '\0';
2348 write (fd
, m
, strlen(m
));
2356 __assert_fail (const char *msg
, const char *file
, unsigned line
, const char *func
)
2358 #define write2(string) write (2, (string), strlen ((string)));
2362 write_itoa (2, (unsigned) pthread_self ());
2365 write2(": assertion failure: `");
2366 write (2, msg
, strlen (msg
));
2368 write (2, func
, strlen (func
));
2370 write (2, file
, strlen (file
));
2372 write_itoa (2, line
);
2383 /* Adapted splay tree code, originally from libiberty. It has been
2384 specialized for libmudflap as requested by RMS. */
2387 mfsplay_tree_free (void *p
)
2389 DECLARE (void, free
, void *p
);
2390 CALL_REAL (free
, p
);
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
,
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
;
2428 comparison
= ((key
> n
->key
) ? 1 : ((key
< n
->key
) ? -1 : 0));
2430 if (comparison
== 0)
2431 /* We've found the target. */
2433 else if (comparison
< 0)
2434 /* The target is to the left. */
2437 /* The target is to the right. */
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;
2450 /* Continue down the tree. */
2452 n
= mfsplay_tree_splay_helper (sp
, key
, next
, node
, parent
);
2455 /* The recursive call will change the place to which NODE
2457 if (*node
!= n
|| sp
->rebalance_p
)
2462 /* NODE is the root. We are done. */
2465 /* First, handle the case where there is no grandparent (i.e.,
2466 *PARENT is the root of the tree.) */
2469 if (n
== (*parent
)->left
)
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
;
2496 else if (n
== (*parent
)->right
&& *parent
== (*grandparent
)->right
)
2498 mfsplay_tree_node p
= *parent
;
2500 (*grandparent
)->right
= p
->left
;
2501 p
->left
= *grandparent
;
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
;
2514 (*grandparent
)->right
= n
->left
;
2515 n
->left
= *grandparent
;
2521 (*parent
)->right
= n
->left
;
2523 (*grandparent
)->left
= n
->right
;
2524 n
->right
= *grandparent
;
2533 mfsplay_tree_rebalance_helper1 (mfsplay_tree_node n
, void *array_ptr
)
2535 mfsplay_tree_node
**p
= array_ptr
;
2542 static mfsplay_tree_node
2543 mfsplay_tree_rebalance_helper2 (mfsplay_tree_node
* array
, unsigned low
,
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);
2556 if (middle
+ 1 <= high
)
2557 n
->right
= mfsplay_tree_rebalance_helper2 (array
, middle
+ 1, high
);
2565 /* Rebalance the entire tree. Do this by copying all the node
2566 pointers into an array, then cleverly re-linking them. */
2568 mfsplay_tree_rebalance (mfsplay_tree sp
)
2570 mfsplay_tree_node
*all_nodes
, *all_nodes_1
;
2572 if (sp
->num_keys
<= 2)
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. */
2591 mfsplay_tree_splay (mfsplay_tree sp
, mfsplay_tree_key key
)
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
))
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
)
2626 /* Cache this splay key. */
2627 sp
->last_splayed_key
= key
;
2628 sp
->last_splayed_key_p
= 1;
2633 /* Allocate a new splay tree. */
2637 mfsplay_tree sp
= mfsplay_tree_xmalloc (sizeof (struct mfsplay_tree_s
));
2639 sp
->last_splayed_key_p
= 0;
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
)
2655 mfsplay_tree_splay (sp
, key
);
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
;
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
));
2674 node
->value
= value
;
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;
2686 node
->right
= sp
->root
;
2687 node
->left
= node
->right
->left
;
2688 node
->right
->left
= 0;
2692 sp
->last_splayed_key_p
= 0;
2698 /* Remove KEY from SP. It is not an error if it did not exist. */
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
);
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. */
2718 /* If there was a right child as well, hang it off the
2719 right-most leaf of the left child. */
2724 left
->right
= right
;
2732 /* Lookup KEY in SP, returning VALUE if present, and NULL
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
))
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
)
2753 mfsplay_tree_node node
;
2754 /* If the tree is empty, there is certainly no predecessor. */
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. */
2766 /* Otherwise, find the rightmost element of the left subtree. */
2767 node
= sp
->root
->left
;
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
)
2781 mfsplay_tree_node node
;
2782 /* If the tree is empty, there is certainly no successor. */
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. */
2793 /* Otherwise, find the leftmost element of the right subtree. */
2794 node
= sp
->root
->right
;
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
2811 mfsplay_tree_foreach (mfsplay_tree st
, mfsplay_tree_foreach_fn fn
, void *data
)
2813 mfsplay_tree_node
*stack1
;
2817 enum s
{ s_left
, s_here
, s_right
, s_up
};
2819 if (st
->root
== NULL
) /* => num_keys == 0 */
2822 stack1
= mfsplay_tree_xmalloc (sizeof (mfsplay_tree_node
) * st
->num_keys
);
2823 stack2
= mfsplay_tree_xmalloc (sizeof (char) * st
->num_keys
);
2826 stack1
[sp
] = st
->root
;
2827 stack2
[sp
] = s_left
;
2831 mfsplay_tree_node n
;
2837 /* Handle each of the four possible states separately. */
2839 /* 1: We're here to traverse the left subtree (if any). */
2842 stack2
[sp
] = s_here
;
2843 if (n
->left
!= NULL
)
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
);
2859 /* 3: We're here to traverse the right subtree (if any). */
2860 else if (s
== s_right
)
2863 if (n
->right
!= NULL
)
2866 stack1
[sp
] = n
->right
;
2867 stack2
[sp
] = s_left
;
2871 /* 4: We're here after both subtrees (if any) have been traversed. */
2874 /* Pop the stack. */
2875 if (sp
== 0) break; /* Popping off the root note: we're finished! */
2883 mfsplay_tree_free (stack1
);
2884 mfsplay_tree_free (stack2
);