Tor  0.4.6.0-alpha-dev
OpenBSD_malloc_Linux.c
1 /* Version 1.83 for Linux.
2  * Compilation: gcc -shared -fPIC -O2 OpenBSD_malloc_Linux.c -o malloc.so
3  * Launching: LD_PRELOAD=/path/to/malloc.so firefox
4  */
5 
6 /* $OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $ */
7 
8 /*
9  * ----------------------------------------------------------------------------
10  * "THE BEER-WARE LICENSE" (Revision 42):
11  * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
12  * can do whatever you want with this stuff. If we meet some day, and you think
13  * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
14  * ----------------------------------------------------------------------------
15  */
16 
17 /* We use this macro to remove some code that we don't actually want,
18  * rather than to fix its warnings. */
19 #define BUILDING_FOR_TOR
20 
21 /*
22  * Defining MALLOC_EXTRA_SANITY will enable extra checks which are
23  * related to internal conditions and consistency in malloc.c. This has
24  * a noticeable runtime performance hit, and generally will not do you
25  * any good unless you fiddle with the internals of malloc or want
26  * to catch random pointer corruption as early as possible.
27  */
28 #ifndef MALLOC_EXTRA_SANITY
29 #undef MALLOC_EXTRA_SANITY
30 #endif
31 
32 /*
33  * Defining MALLOC_STATS will enable you to call malloc_dump() and set
34  * the [dD] options in the MALLOC_OPTIONS environment variable.
35  * It has no run-time performance hit, but does pull in stdio...
36  */
37 #ifndef MALLOC_STATS
38 #undef MALLOC_STATS
39 #endif
40 
41 /*
42  * What to use for Junk. This is the byte value we use to fill with
43  * when the 'J' option is enabled.
44  */
45 #define SOME_JUNK 0xd0 /* as in "Duh" :-) */
46 
47 #include <sys/types.h>
48 #include <sys/time.h>
49 #include <sys/resource.h>
50 #include <sys/param.h>
51 #include <sys/mman.h>
52 #include <sys/uio.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 #include <unistd.h>
57 #include <fcntl.h>
58 #include <limits.h>
59 #include <errno.h>
60 #include <err.h>
61 /* For SIZE_MAX */
62 #include "lib/cc/torint.h"
63 
64 //#include "thread_private.h"
65 
66 /*
67  * The basic parameters you can tweak.
68  *
69  * malloc_pageshift pagesize = 1 << malloc_pageshift
70  * It's probably best if this is the native
71  * page size, but it shouldn't have to be.
72  *
73  * malloc_minsize minimum size of an allocation in bytes.
74  * If this is too small it's too much work
75  * to manage them. This is also the smallest
76  * unit of alignment used for the storage
77  * returned by malloc/realloc.
78  *
79  */
80 
81 static int align = 0;
82 static size_t g_alignment = 0;
83 
84 extern int __libc_enable_secure;
85 
86 #ifndef HAVE_ISSETUGID
87 static int issetugid(void)
88 {
89  if (__libc_enable_secure) return 1;
90  if (getuid() != geteuid()) return 1;
91  if (getgid() != getegid()) return 1;
92  return 0;
93 }
94 #endif
95 
96 #define PGSHIFT 12
97 #undef MADV_FREE
98 #define MADV_FREE MADV_DONTNEED
99 #include <pthread.h>
100 static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
101 
102 #define _MALLOC_LOCK_INIT() {;}
103 #define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
104 #define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
105 
106 #if defined(__sparc__) || defined(__alpha__)
107 #define malloc_pageshift 13U
108 #endif
109 #if defined(__ia64__)
110 #define malloc_pageshift 14U
111 #endif
112 
113 #ifndef malloc_pageshift
114 #define malloc_pageshift (PGSHIFT)
115 #endif
116 
117 /*
118  * No user serviceable parts behind this point.
119  *
120  * This structure describes a page worth of chunks.
121  */
122 struct pginfo {
123  struct pginfo *next; /* next on the free list */
124  void *page; /* Pointer to the page */
125  u_short size; /* size of this page's chunks */
126  u_short shift; /* How far to shift for this size chunks */
127  u_short free; /* How many free chunks */
128  u_short total; /* How many chunk */
129  u_long bits[1];/* Which chunks are free */
130 };
131 
132 /* How many bits per u_long in the bitmap */
133 #define MALLOC_BITS (int)((NBBY * sizeof(u_long)))
134 
135 /*
136  * This structure describes a number of free pages.
137  */
138 struct pgfree {
139  struct pgfree *next; /* next run of free pages */
140  struct pgfree *prev; /* prev run of free pages */
141  void *page; /* pointer to free pages */
142  void *pdir; /* pointer to the base page's dir */
143  size_t size; /* number of bytes free */
144 };
145 
146 /*
147  * Magic values to put in the page_directory
148  */
149 #define MALLOC_NOT_MINE ((struct pginfo*) 0)
150 #define MALLOC_FREE ((struct pginfo*) 1)
151 #define MALLOC_FIRST ((struct pginfo*) 2)
152 #define MALLOC_FOLLOW ((struct pginfo*) 3)
153 #define MALLOC_MAGIC ((struct pginfo*) 4)
154 
155 #ifndef malloc_minsize
156 #define malloc_minsize 16UL
157 #endif
158 
159 #if !defined(malloc_pagesize)
160 #define malloc_pagesize (1UL<<malloc_pageshift)
161 #endif
162 
163 #if ((1UL<<malloc_pageshift) != malloc_pagesize)
164 #error "(1UL<<malloc_pageshift) != malloc_pagesize"
165 #endif
166 
167 #ifndef malloc_maxsize
168 #define malloc_maxsize ((malloc_pagesize)>>1)
169 #endif
170 
171 /* A mask for the offset inside a page. */
172 #define malloc_pagemask ((malloc_pagesize)-1)
173 
174 #define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask)
175 #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
176 #define index2ptr(idx) ((void*)(((idx)-malloc_pageshift)<<malloc_pageshift))
177 
178 /* Set when initialization has been done */
179 static unsigned int malloc_started;
180 
181 /* Number of free pages we cache */
182 static unsigned int malloc_cache = 16;
183 
184 /* Structure used for linking discrete directory pages. */
185 struct pdinfo {
186  struct pginfo **base;
187  struct pdinfo *prev;
188  struct pdinfo *next;
189  u_long dirnum;
190 };
191 static struct pdinfo *last_dir; /* Caches to the last and previous */
192 static struct pdinfo *prev_dir; /* referenced directory pages. */
193 
194 static size_t pdi_off;
195 static u_long pdi_mod;
196 #define PD_IDX(num) ((num) / (malloc_pagesize/sizeof(struct pginfo *)))
197 #define PD_OFF(num) ((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1))
198 #define PI_IDX(index) ((index) / pdi_mod)
199 #define PI_OFF(index) ((index) % pdi_mod)
200 
201 /* The last index in the page directory we care about */
202 static u_long last_index;
203 
204 /* Pointer to page directory. Allocated "as if with" malloc */
205 static struct pginfo **page_dir;
206 
207 /* Free pages line up here */
208 static struct pgfree free_list;
209 
210 /* Abort(), user doesn't handle problems. */
211 static int malloc_abort = 2;
212 
213 /* Are we trying to die ? */
214 static int suicide;
215 
216 #ifdef MALLOC_STATS
217 /* dump statistics */
218 static int malloc_stats;
219 #endif
220 
221 /* avoid outputting warnings? */
222 static int malloc_silent;
223 
224 /* always realloc ? */
225 static int malloc_realloc;
226 
227 /* mprotect free pages PROT_NONE? */
228 static int malloc_freeprot;
229 
230 /* use guard pages after allocations? */
231 static size_t malloc_guard = 0;
232 static size_t malloc_guarded;
233 /* align pointers to end of page? */
234 static int malloc_ptrguard;
235 
236 static int malloc_hint = 1;
237 
238 /* xmalloc behaviour ? */
239 static int malloc_xmalloc;
240 
241 /* zero fill ? */
242 static int malloc_zero;
243 
244 /* junk fill ? */
245 static int malloc_junk;
246 
247 #ifdef __FreeBSD__
248 /* utrace ? */
249 static int malloc_utrace;
250 
251 struct ut {
252  void *p;
253  size_t s;
254  void *r;
255 };
256 
257 void utrace(struct ut *, int);
258 
259 #define UTRACE(a, b, c) \
260  if (malloc_utrace) \
261  {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
262 #else /* !__FreeBSD__ */
263 #define UTRACE(a,b,c)
264 #endif
265 
266 /* Status of malloc. */
267 static int malloc_active;
268 
269 /* Allocated memory. */
270 static size_t malloc_used;
271 
272 /* My last break. */
273 static caddr_t malloc_brk;
274 
275 /* One location cache for free-list holders. */
276 static struct pgfree *px;
277 
278 /* Compile-time options. */
279 char *malloc_options;
280 
281 /* Name of the current public function. */
282 static const char *malloc_func;
283 
284 #define MMAP(size) \
285  mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
286  -1, (off_t)0)
287 
288 /*
289  * Necessary function declarations.
290  */
291 static void *imalloc(size_t size);
292 static void ifree(void *ptr);
293 static void *irealloc(void *ptr, size_t size);
294 static void *malloc_bytes(size_t size);
295 void *memalign(size_t boundary, size_t size);
296 size_t malloc_good_size(size_t size);
297 
298 /*
299  * Function for page directory lookup.
300  */
301 static int
302 pdir_lookup(u_long index, struct pdinfo ** pdi)
303 {
304  struct pdinfo *spi;
305  u_long pidx = PI_IDX(index);
306 
307  if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx)
308  *pdi = last_dir;
309  else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx)
310  *pdi = prev_dir;
311  else if (last_dir != NULL && prev_dir != NULL) {
312  if ((PD_IDX(last_dir->dirnum) > pidx) ?
313  (PD_IDX(last_dir->dirnum) - pidx) :
314  (pidx - PD_IDX(last_dir->dirnum))
315  < (PD_IDX(prev_dir->dirnum) > pidx) ?
316  (PD_IDX(prev_dir->dirnum) - pidx) :
317  (pidx - PD_IDX(prev_dir->dirnum)))
318  *pdi = last_dir;
319  else
320  *pdi = prev_dir;
321 
322  if (PD_IDX((*pdi)->dirnum) > pidx) {
323  for (spi = (*pdi)->prev;
324  spi != NULL && PD_IDX(spi->dirnum) > pidx;
325  spi = spi->prev)
326  *pdi = spi;
327  if (spi != NULL)
328  *pdi = spi;
329  } else
330  for (spi = (*pdi)->next;
331  spi != NULL && PD_IDX(spi->dirnum) <= pidx;
332  spi = spi->next)
333  *pdi = spi;
334  } else {
335  *pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
336  for (spi = *pdi;
337  spi != NULL && PD_IDX(spi->dirnum) <= pidx;
338  spi = spi->next)
339  *pdi = spi;
340  }
341 
342  return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
343  (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
344 }
345 
346 #ifdef MALLOC_STATS
347 void
348 malloc_dump(int fd)
349 {
350  char buf[1024];
351  struct pginfo **pd;
352  struct pgfree *pf;
353  struct pdinfo *pi;
354  u_long j;
355 
356  pd = page_dir;
357  pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
358 
359  /* print out all the pages */
360  for (j = 0; j <= last_index;) {
361  snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j);
362  write(fd, buf, strlen(buf));
363  if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
364  for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
365  if (!PI_OFF(++j)) {
366  if ((pi = pi->next) == NULL ||
367  PD_IDX(pi->dirnum) != PI_IDX(j))
368  break;
369  pd = pi->base;
370  j += pdi_mod;
371  }
372  }
373  j--;
374  snprintf(buf, sizeof buf, ".. %5lu not mine\n", j);
375  write(fd, buf, strlen(buf));
376  } else if (pd[PI_OFF(j)] == MALLOC_FREE) {
377  for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
378  if (!PI_OFF(++j)) {
379  if ((pi = pi->next) == NULL ||
380  PD_IDX(pi->dirnum) != PI_IDX(j))
381  break;
382  pd = pi->base;
383  j += pdi_mod;
384  }
385  }
386  j--;
387  snprintf(buf, sizeof buf, ".. %5lu free\n", j);
388  write(fd, buf, strlen(buf));
389  } else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
390  for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
391  if (!PI_OFF(++j)) {
392  if ((pi = pi->next) == NULL ||
393  PD_IDX(pi->dirnum) != PI_IDX(j))
394  break;
395  pd = pi->base;
396  j += pdi_mod;
397  }
398  }
399  j--;
400  snprintf(buf, sizeof buf, ".. %5lu in use\n", j);
401  write(fd, buf, strlen(buf));
402  } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
403  snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]);
404  write(fd, buf, strlen(buf));
405  } else {
406  snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n",
407  pd[PI_OFF(j)], pd[PI_OFF(j)]->free,
408  pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size,
409  pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next);
410  write(fd, buf, strlen(buf));
411  }
412  if (!PI_OFF(++j)) {
413  if ((pi = pi->next) == NULL)
414  break;
415  pd = pi->base;
416  j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod;
417  }
418  }
419 
420  for (pf = free_list.next; pf; pf = pf->next) {
421  snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
422  pf, pf->page, (char *)pf->page + pf->size,
423  pf->size, pf->prev, pf->next);
424  write(fd, buf, strlen(buf));
425  if (pf == pf->next) {
426  snprintf(buf, sizeof buf, "Free_list loops\n");
427  write(fd, buf, strlen(buf));
428  break;
429  }
430  }
431 
432  /* print out various info */
433  snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize);
434  write(fd, buf, strlen(buf));
435  snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize);
436  write(fd, buf, strlen(buf));
437  snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize);
438  write(fd, buf, strlen(buf));
439  snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift);
440  write(fd, buf, strlen(buf));
441  snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used);
442  write(fd, buf, strlen(buf));
443  snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded);
444  write(fd, buf, strlen(buf));
445 }
446 #endif /* MALLOC_STATS */
447 
448 extern char *__progname;
449 
450 static void
451 wrterror(const char *p)
452 {
453 #ifndef BUILDING_FOR_TOR
454  const char *q = " error: ";
455  struct iovec iov[5];
456 
457  iov[0].iov_base = __progname;
458  iov[0].iov_len = strlen(__progname);
459  iov[1].iov_base = (char*)malloc_func;
460  iov[1].iov_len = strlen(malloc_func);
461  iov[2].iov_base = (char*)q;
462  iov[2].iov_len = strlen(q);
463  iov[3].iov_base = (char*)p;
464  iov[3].iov_len = strlen(p);
465  iov[4].iov_base = (char*)"\n";
466  iov[4].iov_len = 1;
467  writev(STDERR_FILENO, iov, 5);
468 #else
469  (void)p;
470 #endif
471  suicide = 1;
472 #ifdef MALLOC_STATS
473  if (malloc_stats)
474  malloc_dump(STDERR_FILENO);
475 #endif /* MALLOC_STATS */
476  malloc_active--;
477  if (malloc_abort)
478  abort();
479 }
480 
481 static void
482 wrtwarning(const char *p)
483 {
484 #ifndef BUILDING_FOR_TOR
485  const char *q = " warning: ";
486  struct iovec iov[5];
487 #endif
488 
489  if (malloc_abort)
490  wrterror(p);
491  else if (malloc_silent)
492  return;
493 
494 #ifndef BUILDING_FOR_TOR
495  iov[0].iov_base = __progname;
496  iov[0].iov_len = strlen(__progname);
497  iov[1].iov_base = (char*)malloc_func;
498  iov[1].iov_len = strlen(malloc_func);
499  iov[2].iov_base = (char*)q;
500  iov[2].iov_len = strlen(q);
501  iov[3].iov_base = (char*)p;
502  iov[3].iov_len = strlen(p);
503  iov[4].iov_base = (char*)"\n";
504  iov[4].iov_len = 1;
505 
506  (void) writev(STDERR_FILENO, iov, 5);
507 #else
508  (void)p;
509 #endif
510 }
511 
512 #ifdef MALLOC_STATS
513 static void
514 malloc_exit(void)
515 {
516  char *q = "malloc() warning: Couldn't dump stats\n";
517  int save_errno = errno, fd;
518 
519  fd = open("malloc.out", O_RDWR|O_APPEND);
520  if (fd != -1) {
521  malloc_dump(fd);
522  close(fd);
523  } else
524  write(STDERR_FILENO, q, strlen(q));
525  errno = save_errno;
526 }
527 #endif /* MALLOC_STATS */
528 
529 /*
530  * Allocate aligned mmaped chunk
531  */
532 
533 static void *MMAP_A(size_t pages, size_t alignment)
534 {
535  void *j, *p;
536  size_t first_size, rest, begin, end;
537  if (pages%malloc_pagesize != 0)
538  pages = pages - pages%malloc_pagesize + malloc_pagesize;
539  first_size = pages + alignment - malloc_pagesize;
540  p = MMAP(first_size);
541  rest = ((size_t)p) % alignment;
542  j = (rest == 0) ? p : (void*) ((size_t)p + alignment - rest);
543  begin = (size_t)j - (size_t)p;
544  if (begin != 0) munmap(p, begin);
545  end = (size_t)p + first_size - ((size_t)j + pages);
546  if(end != 0) munmap( (void*) ((size_t)j + pages), end);
547 
548  return j;
549 }
550 
551 
552 /*
553  * Allocate a number of pages from the OS
554  */
555 static void *
556 map_pages(size_t pages)
557 {
558  struct pdinfo *pi, *spi;
559  struct pginfo **pd;
560  u_long idx, pidx, lidx;
561  caddr_t result, tail;
562  u_long index, lindex;
563  void *pdregion = NULL;
564  size_t dirs, cnt;
565 
566  pages <<= malloc_pageshift;
567  if (!align)
568  result = MMAP(pages + malloc_guard);
569  else {
570  result = MMAP_A(pages + malloc_guard, g_alignment);
571  }
572  if (result == MAP_FAILED) {
573 #ifdef MALLOC_EXTRA_SANITY
574  wrtwarning("(ES): map_pages fails");
575 #endif /* MALLOC_EXTRA_SANITY */
576  errno = ENOMEM;
577  return (NULL);
578  }
579  index = ptr2index(result);
580  tail = result + pages + malloc_guard;
581  lindex = ptr2index(tail) - 1;
582  if (malloc_guard)
583  mprotect(result + pages, malloc_guard, PROT_NONE);
584 
585  pidx = PI_IDX(index);
586  lidx = PI_IDX(lindex);
587 
588  if (tail > malloc_brk) {
589  malloc_brk = tail;
590  last_index = lindex;
591  }
592 
593  dirs = lidx - pidx;
594 
595  /* Insert directory pages, if needed. */
596  if (pdir_lookup(index, &pi) != 0)
597  dirs++;
598 
599  if (dirs > 0) {
600  pdregion = MMAP(malloc_pagesize * dirs);
601  if (pdregion == MAP_FAILED) {
602  munmap(result, tail - result);
603 #ifdef MALLOC_EXTRA_SANITY
604  wrtwarning("(ES): map_pages fails");
605 #endif
606  errno = ENOMEM;
607  return (NULL);
608  }
609  }
610 
611  cnt = 0;
612  for (idx = pidx, spi = pi; idx <= lidx; idx++) {
613  if (pi == NULL || PD_IDX(pi->dirnum) != idx) {
614  pd = (struct pginfo **)((char *)pdregion +
615  cnt * malloc_pagesize);
616  cnt++;
617  memset(pd, 0, malloc_pagesize);
618  pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
619  pi->base = pd;
620  pi->prev = spi;
621  pi->next = spi->next;
622  pi->dirnum = idx * (malloc_pagesize /
623  sizeof(struct pginfo *));
624 
625  if (spi->next != NULL)
626  spi->next->prev = pi;
627  spi->next = pi;
628  }
629  if (idx > pidx && idx < lidx) {
630  pi->dirnum += pdi_mod;
631  } else if (idx == pidx) {
632  if (pidx == lidx) {
633  pi->dirnum += (u_long)(tail - result) >>
634  malloc_pageshift;
635  } else {
636  pi->dirnum += pdi_mod - PI_OFF(index);
637  }
638  } else {
639  pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
640  }
641 #ifdef MALLOC_EXTRA_SANITY
642  if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > idx) {
643  wrterror("(ES): pages directory overflow");
644  errno = EFAULT;
645  return (NULL);
646  }
647 #endif /* MALLOC_EXTRA_SANITY */
648  if (idx == pidx && pi != last_dir) {
649  prev_dir = last_dir;
650  last_dir = pi;
651  }
652  spi = pi;
653  pi = spi->next;
654  }
655 #ifdef MALLOC_EXTRA_SANITY
656  if (cnt > dirs)
657  wrtwarning("(ES): cnt > dirs");
658 #endif /* MALLOC_EXTRA_SANITY */
659  if (cnt < dirs)
660  munmap((char *)pdregion + cnt * malloc_pagesize,
661  (dirs - cnt) * malloc_pagesize);
662 
663  return (result);
664 }
665 
666 /*
667  * Initialize the world
668  */
669 static void
670 malloc_init(void)
671 {
672  char *p, b[64];
673  int i, j, save_errno = errno;
674 
675  _MALLOC_LOCK_INIT();
676 
677 #ifdef MALLOC_EXTRA_SANITY
678  malloc_junk = 1;
679 #endif /* MALLOC_EXTRA_SANITY */
680 
681  for (i = 0; i < 3; i++) {
682  switch (i) {
683  case 0:
684  j = (int) readlink("/etc/malloc.conf", b, sizeof b - 1);
685  if (j <= 0)
686  continue;
687  b[j] = '\0';
688  p = b;
689  break;
690  case 1:
691  if (issetugid() == 0)
692  p = getenv("MALLOC_OPTIONS");
693  else
694  continue;
695  break;
696  case 2:
697  p = malloc_options;
698  break;
699  default:
700  p = NULL;
701  }
702 
703  for (; p != NULL && *p != '\0'; p++) {
704  switch (*p) {
705  case '>':
706  malloc_cache <<= 1;
707  break;
708  case '<':
709  malloc_cache >>= 1;
710  break;
711  case 'a':
712  malloc_abort = 0;
713  break;
714  case 'A':
715  malloc_abort = 1;
716  break;
717 #ifdef MALLOC_STATS
718  case 'd':
719  malloc_stats = 0;
720  break;
721  case 'D':
722  malloc_stats = 1;
723  break;
724 #endif /* MALLOC_STATS */
725  case 'f':
726  malloc_freeprot = 0;
727  break;
728  case 'F':
729  malloc_freeprot = 1;
730  break;
731  case 'g':
732  malloc_guard = 0;
733  break;
734  case 'G':
735  malloc_guard = malloc_pagesize;
736  break;
737  case 'h':
738  malloc_hint = 0;
739  break;
740  case 'H':
741  malloc_hint = 1;
742  break;
743  case 'j':
744  malloc_junk = 0;
745  break;
746  case 'J':
747  malloc_junk = 1;
748  break;
749  case 'n':
750  malloc_silent = 0;
751  break;
752  case 'N':
753  malloc_silent = 1;
754  break;
755  case 'p':
756  malloc_ptrguard = 0;
757  break;
758  case 'P':
759  malloc_ptrguard = 1;
760  break;
761  case 'r':
762  malloc_realloc = 0;
763  break;
764  case 'R':
765  malloc_realloc = 1;
766  break;
767 #ifdef __FreeBSD__
768  case 'u':
769  malloc_utrace = 0;
770  break;
771  case 'U':
772  malloc_utrace = 1;
773  break;
774 #endif /* __FreeBSD__ */
775  case 'x':
776  malloc_xmalloc = 0;
777  break;
778  case 'X':
779  malloc_xmalloc = 1;
780  break;
781  case 'z':
782  malloc_zero = 0;
783  break;
784  case 'Z':
785  malloc_zero = 1;
786  break;
787  default:
788  j = malloc_abort;
789  malloc_abort = 0;
790  wrtwarning("unknown char in MALLOC_OPTIONS");
791  malloc_abort = j;
792  break;
793  }
794  }
795  }
796 
797  UTRACE(0, 0, 0);
798 
799  /*
800  * We want junk in the entire allocation, and zero only in the part
801  * the user asked for.
802  */
803  if (malloc_zero)
804  malloc_junk = 1;
805 
806 #ifdef MALLOC_STATS
807  if (malloc_stats && (atexit(malloc_exit) == -1))
808  wrtwarning("atexit(2) failed."
809  " Will not be able to dump malloc stats on exit");
810 #endif /* MALLOC_STATS */
811 
812  if (malloc_pagesize != getpagesize()) {
813  wrterror("malloc() replacement compiled with a different "
814  "page size from what we're running with. Failing.");
815  errno = ENOMEM;
816  return;
817  }
818 
819  /* Allocate one page for the page directory. */
820  page_dir = (struct pginfo **)MMAP(malloc_pagesize);
821 
822  if (page_dir == MAP_FAILED) {
823  wrterror("mmap(2) failed, check limits");
824  errno = ENOMEM;
825  return;
826  }
827  pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
828  pdi_mod = pdi_off / sizeof(struct pginfo *);
829 
830  last_dir = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
831  last_dir->base = page_dir;
832  last_dir->prev = last_dir->next = NULL;
833  last_dir->dirnum = malloc_pageshift;
834 
835  /* Been here, done that. */
836  malloc_started++;
837 
838  /* Recalculate the cache size in bytes, and make sure it's nonzero. */
839  if (!malloc_cache)
840  malloc_cache++;
841  malloc_cache <<= malloc_pageshift;
842  errno = save_errno;
843 }
844 
845 /*
846  * Allocate a number of complete pages
847  */
848 static void *
849 malloc_pages(size_t size)
850 {
851  void *p, *delay_free = NULL, *tp;
852  size_t i;
853  struct pginfo **pd;
854  struct pdinfo *pi;
855  u_long pidx, index;
856  struct pgfree *pf;
857 
858  size = pageround(size) + malloc_guard;
859 
860  p = NULL;
861  /* Look for free pages before asking for more */
862  if (!align)
863  for (pf = free_list.next; pf; pf = pf->next) {
864 
865 #ifdef MALLOC_EXTRA_SANITY
866  if (pf->size & malloc_pagemask) {
867  wrterror("(ES): junk length entry on free_list");
868  errno = EFAULT;
869  return (NULL);
870  }
871  if (!pf->size) {
872  wrterror("(ES): zero length entry on free_list");
873  errno = EFAULT;
874  return (NULL);
875  }
876  if (pf->page > (pf->page + pf->size)) {
877  wrterror("(ES): sick entry on free_list");
878  errno = EFAULT;
879  return (NULL);
880  }
881  if ((pi = pf->pdir) == NULL) {
882  wrterror("(ES): invalid page directory on free-list");
883  errno = EFAULT;
884  return (NULL);
885  }
886  if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) {
887  wrterror("(ES): directory index mismatch on free-list");
888  errno = EFAULT;
889  return (NULL);
890  }
891  pd = pi->base;
892  if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) {
893  wrterror("(ES): non-free first page on free-list");
894  errno = EFAULT;
895  return (NULL);
896  }
897  pidx = PI_IDX(ptr2index((pf->page) + (pf->size)) - 1);
898  for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
899  pi = pi->next)
900  ;
901  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
902  wrterror("(ES): last page not referenced in page directory");
903  errno = EFAULT;
904  return (NULL);
905  }
906  pd = pi->base;
907  if (pd[PI_OFF(ptr2index((pf->page) + (pf->size)) - 1)] != MALLOC_FREE) {
908  wrterror("(ES): non-free last page on free-list");
909  errno = EFAULT;
910  return (NULL);
911  }
912 #endif /* MALLOC_EXTRA_SANITY */
913 
914  if (pf->size < size)
915  continue;
916 
917  if (pf->size == size) {
918  p = pf->page;
919  pi = pf->pdir;
920  if (pf->next != NULL)
921  pf->next->prev = pf->prev;
922  pf->prev->next = pf->next;
923  delay_free = pf;
924  break;
925  }
926  p = pf->page;
927  pf->page = (char *) pf->page + size;
928  pf->size -= size;
929  pidx = PI_IDX(ptr2index(pf->page));
930  for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
931  pi = pi->next)
932  ;
933  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
934  wrterror("(ES): hole in directories");
935  errno = EFAULT;
936  return (NULL);
937  }
938  tp = pf->pdir;
939  pf->pdir = pi;
940  pi = tp;
941  break;
942  }
943 
944  size -= malloc_guard;
945 
946 #ifdef MALLOC_EXTRA_SANITY
947  if (p != NULL && pi != NULL) {
948  pidx = PD_IDX(pi->dirnum);
949  pd = pi->base;
950  }
951  if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) {
952  wrterror("(ES): allocated non-free page on free-list");
953  errno = EFAULT;
954  return (NULL);
955  }
956 #endif /* MALLOC_EXTRA_SANITY */
957 
958  if (p != NULL && (malloc_guard || malloc_freeprot))
959  mprotect(p, size, PROT_READ | PROT_WRITE);
960 
961  size >>= malloc_pageshift;
962 
963  /* Map new pages */
964  if (p == NULL)
965  p = map_pages(size);
966 
967  if (p != NULL) {
968  index = ptr2index(p);
969  pidx = PI_IDX(index);
970  pdir_lookup(index, &pi);
971 #ifdef MALLOC_EXTRA_SANITY
972  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
973  wrterror("(ES): mapped pages not found in directory");
974  errno = EFAULT;
975  return (NULL);
976  }
977 #endif /* MALLOC_EXTRA_SANITY */
978  if (pi != last_dir) {
979  prev_dir = last_dir;
980  last_dir = pi;
981  }
982  pd = pi->base;
983  pd[PI_OFF(index)] = MALLOC_FIRST;
984 
985  for (i = 1; i < size; i++) {
986  if (!PI_OFF(index + i)) {
987  pidx++;
988  pi = pi->next;
989 #ifdef MALLOC_EXTRA_SANITY
990  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
991  wrterror("(ES): hole in mapped pages directory");
992  errno = EFAULT;
993  return (NULL);
994  }
995 #endif /* MALLOC_EXTRA_SANITY */
996  pd = pi->base;
997  }
998  pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
999  }
1000  if (malloc_guard) {
1001  if (!PI_OFF(index + i)) {
1002  pidx++;
1003  pi = pi->next;
1004 #ifdef MALLOC_EXTRA_SANITY
1005  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1006  wrterror("(ES): hole in mapped pages directory");
1007  errno = EFAULT;
1008  return (NULL);
1009  }
1010 #endif /* MALLOC_EXTRA_SANITY */
1011  pd = pi->base;
1012  }
1013  pd[PI_OFF(index + i)] = MALLOC_FIRST;
1014  }
1015 
1016  malloc_used += size << malloc_pageshift;
1017  malloc_guarded += malloc_guard;
1018 
1019  if (malloc_junk)
1020  memset(p, SOME_JUNK, size << malloc_pageshift);
1021  }
1022  if (delay_free) {
1023  if (px == NULL)
1024  px = delay_free;
1025  else
1026  ifree(delay_free);
1027  }
1028  return (p);
1029 }
1030 
1031 /*
1032  * Allocate a page of fragments
1033  */
1034 
1035 static __inline__ int
1036 malloc_make_chunks(int bits)
1037 {
1038  struct pginfo *bp, **pd;
1039  struct pdinfo *pi;
1040 #ifdef MALLOC_EXTRA_SANITY
1041  u_long pidx;
1042 #endif /* MALLOC_EXTRA_SANITY */
1043  void *pp;
1044  long i, k;
1045  size_t l;
1046 
1047  /* Allocate a new bucket */
1048  pp = malloc_pages((size_t) malloc_pagesize);
1049  if (pp == NULL)
1050  return (0);
1051 
1052  /* Find length of admin structure */
1053  l = sizeof *bp - sizeof(u_long);
1054  l += sizeof(u_long) *
1055  (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS);
1056 
1057  /* Don't waste more than two chunks on this */
1058 
1059  /*
1060  * If we are to allocate a memory protected page for the malloc(0)
1061  * case (when bits=0), it must be from a different page than the
1062  * pginfo page.
1063  * --> Treat it like the big chunk alloc, get a second data page.
1064  */
1065  if (bits != 0 && (1UL << (bits)) <= l + l) {
1066  bp = (struct pginfo *) pp;
1067  } else {
1068  bp = (struct pginfo *) imalloc(l);
1069  if (bp == NULL) {
1070  ifree(pp);
1071  return (0);
1072  }
1073  }
1074 
1075  /* memory protect the page allocated in the malloc(0) case */
1076  if (bits == 0) {
1077  bp->size = 0;
1078  bp->shift = 1;
1079  i = malloc_minsize - 1;
1080  while (i >>= 1)
1081  bp->shift++;
1082  bp->total = bp->free = malloc_pagesize >> bp->shift;
1083  bp->page = pp;
1084 
1085  k = mprotect(pp, malloc_pagesize, PROT_NONE);
1086  if (k < 0) {
1087  ifree(pp);
1088  ifree(bp);
1089  return (0);
1090  }
1091  } else {
1092  bp->size = (1UL << bits);
1093  bp->shift = bits;
1094  bp->total = bp->free = malloc_pagesize >> bits;
1095  bp->page = pp;
1096  }
1097 
1098  /* set all valid bits in the bitmap */
1099  k = bp->total;
1100  i = 0;
1101 
1102  /* Do a bunch at a time */
1103  for (; (k - i) >= MALLOC_BITS; i += MALLOC_BITS)
1104  bp->bits[i / MALLOC_BITS] = ~0UL;
1105 
1106  for (; i < k; i++)
1107  bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
1108 
1109  k = (long)l;
1110  if (bp == bp->page) {
1111  /* Mark the ones we stole for ourselves */
1112  for (i = 0; k > 0; i++) {
1113  bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS));
1114  bp->free--;
1115  bp->total--;
1116  k -= (1 << bits);
1117  }
1118  }
1119  /* MALLOC_LOCK */
1120 
1121  pdir_lookup(ptr2index(pp), &pi);
1122 #ifdef MALLOC_EXTRA_SANITY
1123  pidx = PI_IDX(ptr2index(pp));
1124  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1125  wrterror("(ES): mapped pages not found in directory");
1126  errno = EFAULT;
1127  return (0);
1128  }
1129 #endif /* MALLOC_EXTRA_SANITY */
1130  if (pi != last_dir) {
1131  prev_dir = last_dir;
1132  last_dir = pi;
1133  }
1134  pd = pi->base;
1135  pd[PI_OFF(ptr2index(pp))] = bp;
1136 
1137  bp->next = page_dir[bits];
1138  page_dir[bits] = bp;
1139 
1140  /* MALLOC_UNLOCK */
1141  return (1);
1142 }
1143 
1144 /*
1145  * Allocate a fragment
1146  */
1147 static void *
1148 malloc_bytes(size_t size)
1149 {
1150  int i, j;
1151  size_t k;
1152  u_long u, *lp;
1153  struct pginfo *bp;
1154 
1155  /* Don't bother with anything less than this */
1156  /* unless we have a malloc(0) requests */
1157  if (size != 0 && size < malloc_minsize)
1158  size = malloc_minsize;
1159 
1160  /* Find the right bucket */
1161  if (size == 0)
1162  j = 0;
1163  else {
1164  size_t ii;
1165  j = 1;
1166  ii = size - 1;
1167  while (ii >>= 1)
1168  j++;
1169  }
1170 
1171  /* If it's empty, make a page more of that size chunks */
1172  if (page_dir[j] == NULL && !malloc_make_chunks(j))
1173  return (NULL);
1174 
1175  bp = page_dir[j];
1176 
1177  /* Find first word of bitmap which isn't empty */
1178  for (lp = bp->bits; !*lp; lp++);
1179 
1180  /* Find that bit, and tweak it */
1181  u = 1;
1182  k = 0;
1183  while (!(*lp & u)) {
1184  u += u;
1185  k++;
1186  }
1187 
1188  if (malloc_guard) {
1189  /* Walk to a random position. */
1190 // i = arc4random() % bp->free;
1191  i = rand() % bp->free;
1192  while (i > 0) {
1193  u += u;
1194  k++;
1195  if (k >= MALLOC_BITS) {
1196  lp++;
1197  u = 1;
1198  k = 0;
1199  }
1200 #ifdef MALLOC_EXTRA_SANITY
1201  if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) {
1202  wrterror("chunk overflow");
1203  errno = EFAULT;
1204  return (NULL);
1205  }
1206 #endif /* MALLOC_EXTRA_SANITY */
1207  if (*lp & u)
1208  i--;
1209  }
1210  }
1211  *lp ^= u;
1212 
1213  /* If there are no more free, remove from free-list */
1214  if (!--bp->free) {
1215  page_dir[j] = bp->next;
1216  bp->next = NULL;
1217  }
1218  /* Adjust to the real offset of that chunk */
1219  k += (lp - bp->bits) * MALLOC_BITS;
1220  k <<= bp->shift;
1221 
1222  if (malloc_junk && bp->size != 0)
1223  memset((char *)bp->page + k, SOME_JUNK, (size_t)bp->size);
1224 
1225  return ((u_char *) bp->page + k);
1226 }
1227 
1228 /*
1229  * Magic so that malloc(sizeof(ptr)) is near the end of the page.
1230  */
1231 #define PTR_GAP (malloc_pagesize - sizeof(void *))
1232 #define PTR_SIZE (sizeof(void *))
1233 #define PTR_ALIGNED(p) (((unsigned long)p & malloc_pagemask) == PTR_GAP)
1234 
1235 /*
1236  * Allocate a piece of memory
1237  */
1238 static void *
1239 imalloc(size_t size)
1240 {
1241  void *result;
1242  int ptralloc = 0;
1243 
1244  if (!malloc_started)
1245  malloc_init();
1246 
1247  if (suicide)
1248  abort();
1249 
1250  /* does not matter if malloc_bytes fails */
1251  if (px == NULL)
1252  px = malloc_bytes(sizeof *px);
1253 
1254  if (malloc_ptrguard && size == PTR_SIZE) {
1255  ptralloc = 1;
1256  size = malloc_pagesize;
1257  }
1258  if (size > SIZE_MAX - malloc_pagesize) { /* Check for overflow */
1259  result = NULL;
1260  errno = ENOMEM;
1261  } else if (size <= malloc_maxsize)
1262  result = malloc_bytes(size);
1263  else
1264  result = malloc_pages(size);
1265 
1266  if (malloc_abort == 1 && result == NULL)
1267  wrterror("allocation failed");
1268 
1269  if (malloc_zero && result != NULL)
1270  memset(result, 0, size);
1271 
1272  if (result && ptralloc)
1273  return ((char *) result + PTR_GAP);
1274  return (result);
1275 }
1276 
1277 /*
1278  * Change the size of an allocation.
1279  */
1280 static void *
1281 irealloc(void *ptr, size_t size)
1282 {
1283  void *p;
1284  size_t osize;
1285  u_long index, i;
1286  struct pginfo **mp;
1287  struct pginfo **pd;
1288  struct pdinfo *pi;
1289 #ifdef MALLOC_EXTRA_SANITY
1290  u_long pidx;
1291 #endif /* MALLOC_EXTRA_SANITY */
1292 
1293  if (suicide)
1294  abort();
1295 
1296  if (!malloc_started) {
1297  wrtwarning("malloc() has never been called");
1298  return (NULL);
1299  }
1300  if (malloc_ptrguard && PTR_ALIGNED(ptr)) {
1301  if (size <= PTR_SIZE)
1302  return (ptr);
1303 
1304  p = imalloc(size);
1305  if (p)
1306  memcpy(p, ptr, PTR_SIZE);
1307  ifree(ptr);
1308  return (p);
1309  }
1310  index = ptr2index(ptr);
1311 
1312  if (index < malloc_pageshift) {
1313  wrtwarning("junk pointer, too low to make sense");
1314  return (NULL);
1315  }
1316  if (index > last_index) {
1317  wrtwarning("junk pointer, too high to make sense");
1318  return (NULL);
1319  }
1320  pdir_lookup(index, &pi);
1321 #ifdef MALLOC_EXTRA_SANITY
1322  pidx = PI_IDX(index);
1323  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1324  wrterror("(ES): mapped pages not found in directory");
1325  errno = EFAULT;
1326  return (NULL);
1327  }
1328 #endif /* MALLOC_EXTRA_SANITY */
1329  if (pi != last_dir) {
1330  prev_dir = last_dir;
1331  last_dir = pi;
1332  }
1333  pd = pi->base;
1334  mp = &pd[PI_OFF(index)];
1335 
1336  if (*mp == MALLOC_FIRST) { /* Page allocation */
1337 
1338  /* Check the pointer */
1339  if ((u_long) ptr & malloc_pagemask) {
1340  wrtwarning("modified (page-) pointer");
1341  return (NULL);
1342  }
1343  /* Find the size in bytes */
1344  i = index;
1345  if (!PI_OFF(++i)) {
1346  pi = pi->next;
1347  if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
1348  pi = NULL;
1349  if (pi != NULL)
1350  pd = pi->base;
1351  }
1352  for (osize = malloc_pagesize;
1353  pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) {
1354  osize += malloc_pagesize;
1355  if (!PI_OFF(++i)) {
1356  pi = pi->next;
1357  if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
1358  pi = NULL;
1359  if (pi != NULL)
1360  pd = pi->base;
1361  }
1362  }
1363 
1364  if (!malloc_realloc && size <= osize &&
1365  size > osize - malloc_pagesize) {
1366  if (malloc_junk)
1367  memset((char *)ptr + size, SOME_JUNK, osize - size);
1368  return (ptr); /* ..don't do anything else. */
1369  }
1370  } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */
1371 
1372  /* Check the pointer for sane values */
1373  if ((u_long) ptr & ((1UL << ((*mp)->shift)) - 1)) {
1374  wrtwarning("modified (chunk-) pointer");
1375  return (NULL);
1376  }
1377  /* Find the chunk index in the page */
1378  i = ((u_long) ptr & malloc_pagemask) >> (*mp)->shift;
1379 
1380  /* Verify that it isn't a free chunk already */
1381  if ((*mp)->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
1382  wrtwarning("chunk is already free");
1383  return (NULL);
1384  }
1385  osize = (*mp)->size;
1386 
1387  if (!malloc_realloc && size <= osize &&
1388  (size > osize / 2 || osize == malloc_minsize)) {
1389  if (malloc_junk)
1390  memset((char *) ptr + size, SOME_JUNK, osize - size);
1391  return (ptr); /* ..don't do anything else. */
1392  }
1393  } else {
1394  wrtwarning("irealloc: pointer to wrong page");
1395  return (NULL);
1396  }
1397 
1398  p = imalloc(size);
1399 
1400  if (p != NULL) {
1401  /* copy the lesser of the two sizes, and free the old one */
1402  /* Don't move from/to 0 sized region !!! */
1403  if (osize != 0 && size != 0) {
1404  if (osize < size)
1405  memcpy(p, ptr, osize);
1406  else
1407  memcpy(p, ptr, size);
1408  }
1409  ifree(ptr);
1410  }
1411  return (p);
1412 }
1413 
1414 /*
1415  * Free a sequence of pages
1416  */
1417 static __inline__ void
1418 free_pages(void *ptr, u_long index, struct pginfo * info)
1419 {
1420  u_long i, pidx, lidx;
1421  size_t l, cachesize = 0;
1422  struct pginfo **pd;
1423  struct pdinfo *pi, *spi;
1424  struct pgfree *pf, *pt = NULL;
1425  caddr_t tail;
1426 
1427  if (info == MALLOC_FREE) {
1428  wrtwarning("page is already free");
1429  return;
1430  }
1431  if (info != MALLOC_FIRST) {
1432  wrtwarning("free_pages: pointer to wrong page");
1433  return;
1434  }
1435  if ((u_long) ptr & malloc_pagemask) {
1436  wrtwarning("modified (page-) pointer");
1437  return;
1438  }
1439  /* Count how many pages and mark them free at the same time */
1440  pidx = PI_IDX(index);
1441  pdir_lookup(index, &pi);
1442 #ifdef MALLOC_EXTRA_SANITY
1443  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1444  wrterror("(ES): mapped pages not found in directory");
1445  errno = EFAULT;
1446  return;
1447  }
1448 #endif /* MALLOC_EXTRA_SANITY */
1449 
1450  spi = pi; /* Save page index for start of region. */
1451 
1452  pd = pi->base;
1453  pd[PI_OFF(index)] = MALLOC_FREE;
1454  i = 1;
1455  if (!PI_OFF(index + i)) {
1456  pi = pi->next;
1457  if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i))
1458  pi = NULL;
1459  else
1460  pd = pi->base;
1461  }
1462  while (pi != NULL && pd[PI_OFF(index + i)] == MALLOC_FOLLOW) {
1463  pd[PI_OFF(index + i)] = MALLOC_FREE;
1464  i++;
1465  if (!PI_OFF(index + i)) {
1466  if ((pi = pi->next) == NULL ||
1467  PD_IDX(pi->dirnum) != PI_IDX(index + i))
1468  pi = NULL;
1469  else
1470  pd = pi->base;
1471  }
1472  }
1473 
1474  l = i << malloc_pageshift;
1475 
1476  if (malloc_junk)
1477  memset(ptr, SOME_JUNK, l);
1478 
1479  malloc_used -= l;
1480  malloc_guarded -= malloc_guard;
1481  if (malloc_guard) {
1482 #ifdef MALLOC_EXTRA_SANITY
1483  if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index + i)) {
1484  wrterror("(ES): hole in mapped pages directory");
1485  errno = EFAULT;
1486  return;
1487  }
1488 #endif /* MALLOC_EXTRA_SANITY */
1489  pd[PI_OFF(index + i)] = MALLOC_FREE;
1490  l += malloc_guard;
1491  }
1492  tail = (caddr_t)ptr + l;
1493 
1494  if (malloc_hint)
1495  madvise(ptr, l, MADV_FREE);
1496 
1497  if (malloc_freeprot)
1498  mprotect(ptr, l, PROT_NONE);
1499 
1500  /* Add to free-list. */
1501  if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL)
1502  goto not_return;
1503  px->page = ptr;
1504  px->pdir = spi;
1505  px->size = l;
1506 
1507  if (free_list.next == NULL) {
1508  /* Nothing on free list, put this at head. */
1509  px->next = NULL;
1510  px->prev = &free_list;
1511  free_list.next = px;
1512  pf = px;
1513  px = NULL;
1514  } else {
1515  /*
1516  * Find the right spot, leave pf pointing to the modified
1517  * entry.
1518  */
1519 
1520  /* Race ahead here, while calculating cache size. */
1521  for (pf = free_list.next;
1522  (caddr_t)ptr > ((caddr_t)pf->page + pf->size)
1523  && pf->next != NULL;
1524  pf = pf->next)
1525  cachesize += pf->size;
1526 
1527  /* Finish cache size calculation. */
1528  pt = pf;
1529  while (pt) {
1530  cachesize += pt->size;
1531  pt = pt->next;
1532  }
1533 
1534  if ((caddr_t)pf->page > tail) {
1535  /* Insert before entry */
1536  px->next = pf;
1537  px->prev = pf->prev;
1538  pf->prev = px;
1539  px->prev->next = px;
1540  pf = px;
1541  px = NULL;
1542  } else if (((caddr_t)pf->page + pf->size) == ptr) {
1543  /* Append to the previous entry. */
1544  cachesize -= pf->size;
1545  pf->size += l;
1546  if (pf->next != NULL &&
1547  pf->next->page == ((caddr_t)pf->page + pf->size)) {
1548  /* And collapse the next too. */
1549  pt = pf->next;
1550  pf->size += pt->size;
1551  pf->next = pt->next;
1552  if (pf->next != NULL)
1553  pf->next->prev = pf;
1554  }
1555  } else if (pf->page == tail) {
1556  /* Prepend to entry. */
1557  cachesize -= pf->size;
1558  pf->size += l;
1559  pf->page = ptr;
1560  pf->pdir = spi;
1561  } else if (pf->next == NULL) {
1562  /* Append at tail of chain. */
1563  px->next = NULL;
1564  px->prev = pf;
1565  pf->next = px;
1566  pf = px;
1567  px = NULL;
1568  } else {
1569  wrterror("freelist is destroyed");
1570  errno = EFAULT;
1571  return;
1572  }
1573  }
1574 
1575  if (pf->pdir != last_dir) {
1576  prev_dir = last_dir;
1577  last_dir = pf->pdir;
1578  }
1579 
1580  /* Return something to OS ? */
1581  if (pf->size > (malloc_cache - cachesize)) {
1582 
1583  /*
1584  * Keep the cache intact. Notice that the '>' above guarantees that
1585  * the pf will always have at least one page afterwards.
1586  */
1587  if (munmap((char *) pf->page + (malloc_cache - cachesize),
1588  pf->size - (malloc_cache - cachesize)) != 0)
1589  goto not_return;
1590  tail = (caddr_t)pf->page + pf->size;
1591  lidx = ptr2index(tail) - 1;
1592  pf->size = malloc_cache - cachesize;
1593 
1594  index = ptr2index((caddr_t)pf->page + pf->size);
1595 
1596  pidx = PI_IDX(index);
1597  if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) >= pidx)
1598  prev_dir = NULL; /* Will be wiped out below ! */
1599 
1600  for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
1601  pi = pi->next)
1602  ;
1603 
1604  spi = pi;
1605  if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
1606  pd = pi->base;
1607 
1608  for (i = index; i <= lidx;) {
1609  if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) {
1610  pd[PI_OFF(i)] = MALLOC_NOT_MINE;
1611 #ifdef MALLOC_EXTRA_SANITY
1612  if (!PD_OFF(pi->dirnum)) {
1613  wrterror("(ES): pages directory underflow");
1614  errno = EFAULT;
1615  return;
1616  }
1617 #endif /* MALLOC_EXTRA_SANITY */
1618  pi->dirnum--;
1619  }
1620 #ifdef MALLOC_EXTRA_SANITY
1621  else
1622  wrtwarning("(ES): page already unmapped");
1623 #endif /* MALLOC_EXTRA_SANITY */
1624  i++;
1625  if (!PI_OFF(i)) {
1626  /*
1627  * If no page in that dir, free
1628  * directory page.
1629  */
1630  if (!PD_OFF(pi->dirnum)) {
1631  /* Remove from list. */
1632  if (spi == pi)
1633  spi = pi->prev;
1634  if (pi->prev != NULL)
1635  pi->prev->next = pi->next;
1636  if (pi->next != NULL)
1637  pi->next->prev = pi->prev;
1638  pi = pi->next;
1639  munmap(pd, malloc_pagesize);
1640  } else
1641  pi = pi->next;
1642  if (pi == NULL ||
1643  PD_IDX(pi->dirnum) != PI_IDX(i))
1644  break;
1645  pd = pi->base;
1646  }
1647  }
1648  if (pi && !PD_OFF(pi->dirnum)) {
1649  /* Resulting page dir is now empty. */
1650  /* Remove from list. */
1651  if (spi == pi) /* Update spi only if first. */
1652  spi = pi->prev;
1653  if (pi->prev != NULL)
1654  pi->prev->next = pi->next;
1655  if (pi->next != NULL)
1656  pi->next->prev = pi->prev;
1657  pi = pi->next;
1658  munmap(pd, malloc_pagesize);
1659  }
1660  }
1661  if (pi == NULL && malloc_brk == tail) {
1662  /* Resize down the malloc upper boundary. */
1663  last_index = index - 1;
1664  malloc_brk = index2ptr(index);
1665  }
1666 
1667  /* XXX: We could realloc/shrink the pagedir here I guess. */
1668  if (pf->size == 0) { /* Remove from free-list as well. */
1669  if (px)
1670  ifree(px);
1671  if ((px = pf->prev) != &free_list) {
1672  if (pi == NULL && last_index == (index - 1)) {
1673  if (spi == NULL) {
1674  malloc_brk = NULL;
1675  i = 11;
1676  } else {
1677  pd = spi->base;
1678  if (PD_IDX(spi->dirnum) < pidx)
1679  index =
1680  ((PD_IDX(spi->dirnum) + 1) *
1681  pdi_mod) - 1;
1682  for (pi = spi, i = index;
1683  pd[PI_OFF(i)] == MALLOC_NOT_MINE;
1684  i--)
1685 #ifdef MALLOC_EXTRA_SANITY
1686  if (!PI_OFF(i)) {
1687  pi = pi->prev;
1688  if (pi == NULL || i == 0)
1689  break;
1690  pd = pi->base;
1691  i = (PD_IDX(pi->dirnum) + 1) * pdi_mod;
1692  }
1693 #else /* !MALLOC_EXTRA_SANITY */
1694  {
1695  }
1696 #endif /* MALLOC_EXTRA_SANITY */
1697  malloc_brk = index2ptr(i + 1);
1698  }
1699  last_index = i;
1700  }
1701  if ((px->next = pf->next) != NULL)
1702  px->next->prev = px;
1703  } else {
1704  if ((free_list.next = pf->next) != NULL)
1705  free_list.next->prev = &free_list;
1706  }
1707  px = pf;
1708  last_dir = prev_dir;
1709  prev_dir = NULL;
1710  }
1711  }
1712 not_return:
1713  if (pt != NULL)
1714  ifree(pt);
1715 }
1716 
1717 /*
1718  * Free a chunk, and possibly the page it's on, if the page becomes empty.
1719  */
1720 
1721 /* ARGSUSED */
1722 static __inline__ void
1723 free_bytes(void *ptr, u_long index, struct pginfo * info)
1724 {
1725  struct pginfo **mp, **pd;
1726  struct pdinfo *pi;
1727 #ifdef MALLOC_EXTRA_SANITY
1728  u_long pidx;
1729 #endif /* MALLOC_EXTRA_SANITY */
1730  void *vp;
1731  long i;
1732  (void) index;
1733 
1734  /* Find the chunk number on the page */
1735  i = ((u_long) ptr & malloc_pagemask) >> info->shift;
1736 
1737  if ((u_long) ptr & ((1UL << (info->shift)) - 1)) {
1738  wrtwarning("modified (chunk-) pointer");
1739  return;
1740  }
1741  if (info->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
1742  wrtwarning("chunk is already free");
1743  return;
1744  }
1745  if (malloc_junk && info->size != 0)
1746  memset(ptr, SOME_JUNK, (size_t)info->size);
1747 
1748  info->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
1749  info->free++;
1750 
1751  if (info->size != 0)
1752  mp = page_dir + info->shift;
1753  else
1754  mp = page_dir;
1755 
1756  if (info->free == 1) {
1757  /* Page became non-full */
1758 
1759  /* Insert in address order */
1760  while (*mp != NULL && (*mp)->next != NULL &&
1761  (*mp)->next->page < info->page)
1762  mp = &(*mp)->next;
1763  info->next = *mp;
1764  *mp = info;
1765  return;
1766  }
1767  if (info->free != info->total)
1768  return;
1769 
1770  /* Find & remove this page in the queue */
1771  while (*mp != info) {
1772  mp = &((*mp)->next);
1773 #ifdef MALLOC_EXTRA_SANITY
1774  if (!*mp) {
1775  wrterror("(ES): Not on queue");
1776  errno = EFAULT;
1777  return;
1778  }
1779 #endif /* MALLOC_EXTRA_SANITY */
1780  }
1781  *mp = info->next;
1782 
1783  /* Free the page & the info structure if need be */
1784  pdir_lookup(ptr2index(info->page), &pi);
1785 #ifdef MALLOC_EXTRA_SANITY
1786  pidx = PI_IDX(ptr2index(info->page));
1787  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1788  wrterror("(ES): mapped pages not found in directory");
1789  errno = EFAULT;
1790  return;
1791  }
1792 #endif /* MALLOC_EXTRA_SANITY */
1793  if (pi != last_dir) {
1794  prev_dir = last_dir;
1795  last_dir = pi;
1796  }
1797  pd = pi->base;
1798  pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
1799 
1800  /* If the page was mprotected, unprotect it before releasing it */
1801  if (info->size == 0)
1802  mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE);
1803 
1804  vp = info->page; /* Order is important ! */
1805  if (vp != (void *) info)
1806  ifree(info);
1807  ifree(vp);
1808 }
1809 
1810 static void
1811 ifree(void *ptr)
1812 {
1813  struct pginfo *info, **pd;
1814  u_long index;
1815 #ifdef MALLOC_EXTRA_SANITY
1816  u_long pidx;
1817 #endif /* MALLOC_EXTRA_SANITY */
1818  struct pdinfo *pi;
1819 
1820  if (!malloc_started) {
1821  wrtwarning("malloc() has never been called");
1822  return;
1823  }
1824  /* If we're already sinking, don't make matters any worse. */
1825  if (suicide)
1826  return;
1827 
1828  if (malloc_ptrguard && PTR_ALIGNED(ptr))
1829  ptr = (char *) ptr - PTR_GAP;
1830 
1831  index = ptr2index(ptr);
1832 
1833  if (index < malloc_pageshift) {
1834  warnx("(%p)", ptr);
1835  wrtwarning("ifree: junk pointer, too low to make sense");
1836  return;
1837  }
1838  if (index > last_index) {
1839  warnx("(%p)", ptr);
1840  wrtwarning("ifree: junk pointer, too high to make sense");
1841  return;
1842  }
1843  pdir_lookup(index, &pi);
1844 #ifdef MALLOC_EXTRA_SANITY
1845  pidx = PI_IDX(index);
1846  if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
1847  wrterror("(ES): mapped pages not found in directory");
1848  errno = EFAULT;
1849  return;
1850  }
1851 #endif /* MALLOC_EXTRA_SANITY */
1852  if (pi != last_dir) {
1853  prev_dir = last_dir;
1854  last_dir = pi;
1855  }
1856  pd = pi->base;
1857  info = pd[PI_OFF(index)];
1858 
1859  if (info < MALLOC_MAGIC)
1860  free_pages(ptr, index, info);
1861  else
1862  free_bytes(ptr, index, info);
1863 
1864  /* does not matter if malloc_bytes fails */
1865  if (px == NULL)
1866  px = malloc_bytes(sizeof *px);
1867 
1868  return;
1869 }
1870 
1871 /*
1872  * Common function for handling recursion. Only
1873  * print the error message once, to avoid making the problem
1874  * potentially worse.
1875  */
1876 static void
1877 malloc_recurse(void)
1878 {
1879  static int noprint;
1880 
1881  if (noprint == 0) {
1882  noprint = 1;
1883  wrtwarning("recursive call");
1884  }
1885  malloc_active--;
1886  _MALLOC_UNLOCK();
1887  errno = EDEADLK;
1888 }
1889 
1890 /*
1891  * These are the public exported interface routines.
1892  */
1893 void *
1894 malloc(size_t size)
1895 {
1896  void *r;
1897 
1898  if (!align)
1899  _MALLOC_LOCK();
1900  malloc_func = " in malloc():";
1901  if (malloc_active++) {
1902  malloc_recurse();
1903  return (NULL);
1904  }
1905  r = imalloc(size);
1906  UTRACE(0, size, r);
1907  malloc_active--;
1908  if (!align)
1909  _MALLOC_UNLOCK();
1910  if (malloc_xmalloc && r == NULL) {
1911  wrterror("out of memory");
1912  errno = ENOMEM;
1913  }
1914  return (r);
1915 }
1916 
1917 void
1918 free(void *ptr)
1919 {
1920  /* This is legal. XXX quick path */
1921  if (ptr == NULL)
1922  return;
1923 
1924  _MALLOC_LOCK();
1925  malloc_func = " in free():";
1926  if (malloc_active++) {
1927  malloc_recurse();
1928  return;
1929  }
1930  ifree(ptr);
1931  UTRACE(ptr, 0, 0);
1932  malloc_active--;
1933  _MALLOC_UNLOCK();
1934  return;
1935 }
1936 
1937 void *
1938 realloc(void *ptr, size_t size)
1939 {
1940  void *r;
1941 
1942  _MALLOC_LOCK();
1943  malloc_func = " in realloc():";
1944  if (malloc_active++) {
1945  malloc_recurse();
1946  return (NULL);
1947  }
1948 
1949  if (ptr == NULL)
1950  r = imalloc(size);
1951  else
1952  r = irealloc(ptr, size);
1953 
1954  UTRACE(ptr, size, r);
1955  malloc_active--;
1956  _MALLOC_UNLOCK();
1957  if (malloc_xmalloc && r == NULL) {
1958  wrterror("out of memory");
1959  errno = ENOMEM;
1960  }
1961  return (r);
1962 }
1963 
1964 void *
1965 calloc(size_t num, size_t size)
1966 {
1967  void *p;
1968 
1969  if (num && SIZE_MAX / num < size) {
1970  fprintf(stderr,"OOOOPS");
1971  errno = ENOMEM;
1972  return NULL;
1973  }
1974  size *= num;
1975  p = malloc(size);
1976  if (p)
1977  memset(p, 0, size);
1978  return(p);
1979 }
1980 
1981 #ifndef BUILDING_FOR_TOR
1982 static int ispowerof2 (size_t a) {
1983  size_t b;
1984  for (b = 1ULL << (sizeof(size_t)*NBBY - 1); b > 1; b >>= 1)
1985  if (b == a)
1986  return 1;
1987  return 0;
1988 }
1989 #endif
1990 
1991 #ifndef BUILDING_FOR_TOR
1992 int posix_memalign(void **memptr, size_t alignment, size_t size)
1993 {
1994  void *r;
1995  size_t max;
1996  if ((alignment < PTR_SIZE) || (alignment%PTR_SIZE != 0)) return EINVAL;
1997  if (!ispowerof2(alignment)) return EINVAL;
1998  if (alignment < malloc_minsize) alignment = malloc_minsize;
1999  max = alignment > size ? alignment : size;
2000  if (alignment <= malloc_pagesize)
2001  r = malloc(max);
2002  else {
2003  _MALLOC_LOCK();
2004  align = 1;
2005  g_alignment = alignment;
2006  r = malloc(size);
2007  align=0;
2008  _MALLOC_UNLOCK();
2009  }
2010  *memptr = r;
2011  if (!r) return ENOMEM;
2012  return 0;
2013 }
2014 
2015 void *memalign(size_t boundary, size_t size)
2016 {
2017  void *r;
2018  posix_memalign(&r, boundary, size);
2019  return r;
2020 }
2021 
2022 void *valloc(size_t size)
2023 {
2024  void *r;
2025  posix_memalign(&r, malloc_pagesize, size);
2026  return r;
2027 }
2028 #endif
2029 
2030 size_t malloc_good_size(size_t size)
2031 {
2032  if (size == 0) {
2033  return 1;
2034  } else if (size <= malloc_maxsize) {
2035  int j;
2036  size_t ii;
2037  /* round up to the nearest power of 2, with same approach
2038  * as malloc_bytes() uses. */
2039  j = 1;
2040  ii = size - 1;
2041  while (ii >>= 1)
2042  j++;
2043  return ((size_t)1) << j;
2044  } else {
2045  return pageround(size);
2046  }
2047 }
torint.h
Integer definitions used throughout Tor.
pgfree
Definition: OpenBSD_malloc_Linux.c:138
pginfo
Definition: OpenBSD_malloc_Linux.c:122
pdinfo
Definition: OpenBSD_malloc_Linux.c:185