Merge branch 'tor-gitlab/mr/443'
[tor.git] / src / ext / OpenBSD_malloc_Linux.c
blob9c30570c411808fcf849030eb37837d0de3878c1
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 */
6 /* $OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $ */
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 * ----------------------------------------------------------------------------
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
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.
28 #ifndef MALLOC_EXTRA_SANITY
29 #undef MALLOC_EXTRA_SANITY
30 #endif
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...
37 #ifndef MALLOC_STATS
38 #undef MALLOC_STATS
39 #endif
42 * What to use for Junk. This is the byte value we use to fill with
43 * when the 'J' option is enabled.
45 #define SOME_JUNK 0xd0 /* as in "Duh" :-) */
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"
64 //#include "thread_private.h"
67 * The basic parameters you can tweak.
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.
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.
81 static int align = 0;
82 static size_t g_alignment = 0;
84 extern int __libc_enable_secure;
86 #ifndef HAVE_ISSETUGID
87 static int issetugid(void)
89 if (__libc_enable_secure) return 1;
90 if (getuid() != geteuid()) return 1;
91 if (getgid() != getegid()) return 1;
92 return 0;
94 #endif
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;
102 #define _MALLOC_LOCK_INIT() {;}
103 #define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
104 #define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
106 #if defined(__sparc__) || defined(__alpha__)
107 #define malloc_pageshift 13U
108 #endif
109 #if defined(__ia64__)
110 #define malloc_pageshift 14U
111 #endif
113 #ifndef malloc_pageshift
114 #define malloc_pageshift (PGSHIFT)
115 #endif
118 * No user serviceable parts behind this point.
120 * This structure describes a page worth of chunks.
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 */
132 /* How many bits per u_long in the bitmap */
133 #define MALLOC_BITS (int)((NBBY * sizeof(u_long)))
136 * This structure describes a number of free pages.
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 */
147 * Magic values to put in the page_directory
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)
155 #ifndef malloc_minsize
156 #define malloc_minsize 16UL
157 #endif
159 #if !defined(malloc_pagesize)
160 #define malloc_pagesize (1UL<<malloc_pageshift)
161 #endif
163 #if ((1UL<<malloc_pageshift) != malloc_pagesize)
164 #error "(1UL<<malloc_pageshift) != malloc_pagesize"
165 #endif
167 #ifndef malloc_maxsize
168 #define malloc_maxsize ((malloc_pagesize)>>1)
169 #endif
171 /* A mask for the offset inside a page. */
172 #define malloc_pagemask ((malloc_pagesize)-1)
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))
178 /* Set when initialization has been done */
179 static unsigned int malloc_started;
181 /* Number of free pages we cache */
182 static unsigned int malloc_cache = 16;
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;
191 static struct pdinfo *last_dir; /* Caches to the last and previous */
192 static struct pdinfo *prev_dir; /* referenced directory pages. */
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)
201 /* The last index in the page directory we care about */
202 static u_long last_index;
204 /* Pointer to page directory. Allocated "as if with" malloc */
205 static struct pginfo **page_dir;
207 /* Free pages line up here */
208 static struct pgfree free_list;
210 /* Abort(), user doesn't handle problems. */
211 static int malloc_abort = 2;
213 /* Are we trying to die ? */
214 static int suicide;
216 #ifdef MALLOC_STATS
217 /* dump statistics */
218 static int malloc_stats;
219 #endif
221 /* avoid outputting warnings? */
222 static int malloc_silent;
224 /* always realloc ? */
225 static int malloc_realloc;
227 /* mprotect free pages PROT_NONE? */
228 static int malloc_freeprot;
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;
236 static int malloc_hint = 1;
238 /* xmalloc behaviour ? */
239 static int malloc_xmalloc;
241 /* zero fill ? */
242 static int malloc_zero;
244 /* junk fill ? */
245 static int malloc_junk;
247 #ifdef __FreeBSD__
248 /* utrace ? */
249 static int malloc_utrace;
251 struct ut {
252 void *p;
253 size_t s;
254 void *r;
257 void utrace(struct ut *, int);
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
266 /* Status of malloc. */
267 static int malloc_active;
269 /* Allocated memory. */
270 static size_t malloc_used;
272 /* My last break. */
273 static caddr_t malloc_brk;
275 /* One location cache for free-list holders. */
276 static struct pgfree *px;
278 /* Compile-time options. */
279 char *malloc_options;
281 /* Name of the current public function. */
282 static const char *malloc_func;
284 #define MMAP(size) \
285 mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
286 -1, (off_t)0)
289 * Necessary function declarations.
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);
299 * Function for page directory lookup.
301 static int
302 pdir_lookup(u_long index, struct pdinfo ** pdi)
304 struct pdinfo *spi;
305 u_long pidx = PI_IDX(index);
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;
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;
342 return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
343 (PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
346 #ifdef MALLOC_STATS
347 void
348 malloc_dump(int fd)
350 char buf[1024];
351 struct pginfo **pd;
352 struct pgfree *pf;
353 struct pdinfo *pi;
354 u_long j;
356 pd = page_dir;
357 pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
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;
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;
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;
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));
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;
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;
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));
446 #endif /* MALLOC_STATS */
448 extern char *__progname;
450 static void
451 wrterror(const char *p)
453 #ifndef BUILDING_FOR_TOR
454 const char *q = " error: ";
455 struct iovec iov[5];
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();
481 static void
482 wrtwarning(const char *p)
484 #ifndef BUILDING_FOR_TOR
485 const char *q = " warning: ";
486 struct iovec iov[5];
487 #endif
489 if (malloc_abort)
490 wrterror(p);
491 else if (malloc_silent)
492 return;
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;
506 (void) writev(STDERR_FILENO, iov, 5);
507 #else
508 (void)p;
509 #endif
512 #ifdef MALLOC_STATS
513 static void
514 malloc_exit(void)
516 char *q = "malloc() warning: Couldn't dump stats\n";
517 int save_errno = errno, fd;
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;
527 #endif /* MALLOC_STATS */
530 * Allocate aligned mmaped chunk
533 static void *MMAP_A(size_t pages, size_t alignment)
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);
548 return j;
553 * Allocate a number of pages from the OS
555 static void *
556 map_pages(size_t pages)
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;
566 pages <<= malloc_pageshift;
567 if (!align)
568 result = MMAP(pages + malloc_guard);
569 else {
570 result = MMAP_A(pages + malloc_guard, g_alignment);
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);
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);
585 pidx = PI_IDX(index);
586 lidx = PI_IDX(lindex);
588 if (tail > malloc_brk) {
589 malloc_brk = tail;
590 last_index = lindex;
593 dirs = lidx - pidx;
595 /* Insert directory pages, if needed. */
596 if (pdir_lookup(index, &pi) != 0)
597 dirs++;
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);
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 *));
625 if (spi->next != NULL)
626 spi->next->prev = pi;
627 spi->next = pi;
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);
638 } else {
639 pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
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);
647 #endif /* MALLOC_EXTRA_SANITY */
648 if (idx == pidx && pi != last_dir) {
649 prev_dir = last_dir;
650 last_dir = pi;
652 spi = pi;
653 pi = spi->next;
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);
663 return (result);
667 * Initialize the world
669 static void
670 malloc_init(void)
672 char *p, b[64];
673 int i, j, save_errno = errno;
675 _MALLOC_LOCK_INIT();
677 #ifdef MALLOC_EXTRA_SANITY
678 malloc_junk = 1;
679 #endif /* MALLOC_EXTRA_SANITY */
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;
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;
797 UTRACE(0, 0, 0);
800 * We want junk in the entire allocation, and zero only in the part
801 * the user asked for.
803 if (malloc_zero)
804 malloc_junk = 1;
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 */
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;
819 /* Allocate one page for the page directory. */
820 page_dir = (struct pginfo **)MMAP(malloc_pagesize);
822 if (page_dir == MAP_FAILED) {
823 wrterror("mmap(2) failed, check limits");
824 errno = ENOMEM;
825 return;
827 pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
828 pdi_mod = pdi_off / sizeof(struct pginfo *);
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;
835 /* Been here, done that. */
836 malloc_started++;
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;
846 * Allocate a number of complete pages
848 static void *
849 malloc_pages(size_t size)
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;
858 size = pageround(size) + malloc_guard;
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) {
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);
871 if (!pf->size) {
872 wrterror("(ES): zero length entry on free_list");
873 errno = EFAULT;
874 return (NULL);
876 if (pf->page > (pf->page + pf->size)) {
877 wrterror("(ES): sick entry on free_list");
878 errno = EFAULT;
879 return (NULL);
881 if ((pi = pf->pdir) == NULL) {
882 wrterror("(ES): invalid page directory on free-list");
883 errno = EFAULT;
884 return (NULL);
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);
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);
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)
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);
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);
912 #endif /* MALLOC_EXTRA_SANITY */
914 if (pf->size < size)
915 continue;
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;
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)
933 if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
934 wrterror("(ES): hole in directories");
935 errno = EFAULT;
936 return (NULL);
938 tp = pf->pdir;
939 pf->pdir = pi;
940 pi = tp;
941 break;
944 size -= malloc_guard;
946 #ifdef MALLOC_EXTRA_SANITY
947 if (p != NULL && pi != NULL) {
948 pidx = PD_IDX(pi->dirnum);
949 pd = pi->base;
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);
956 #endif /* MALLOC_EXTRA_SANITY */
958 if (p != NULL && (malloc_guard || malloc_freeprot))
959 mprotect(p, size, PROT_READ | PROT_WRITE);
961 size >>= malloc_pageshift;
963 /* Map new pages */
964 if (p == NULL)
965 p = map_pages(size);
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);
977 #endif /* MALLOC_EXTRA_SANITY */
978 if (pi != last_dir) {
979 prev_dir = last_dir;
980 last_dir = pi;
982 pd = pi->base;
983 pd[PI_OFF(index)] = MALLOC_FIRST;
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);
995 #endif /* MALLOC_EXTRA_SANITY */
996 pd = pi->base;
998 pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
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);
1010 #endif /* MALLOC_EXTRA_SANITY */
1011 pd = pi->base;
1013 pd[PI_OFF(index + i)] = MALLOC_FIRST;
1016 malloc_used += size << malloc_pageshift;
1017 malloc_guarded += malloc_guard;
1019 if (malloc_junk)
1020 memset(p, SOME_JUNK, size << malloc_pageshift);
1022 if (delay_free) {
1023 if (px == NULL)
1024 px = delay_free;
1025 else
1026 ifree(delay_free);
1028 return (p);
1032 * Allocate a page of fragments
1035 static __inline__ int
1036 malloc_make_chunks(int bits)
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;
1047 /* Allocate a new bucket */
1048 pp = malloc_pages((size_t) malloc_pagesize);
1049 if (pp == NULL)
1050 return (0);
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);
1057 /* Don't waste more than two chunks on this */
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.
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);
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;
1085 k = mprotect(pp, malloc_pagesize, PROT_NONE);
1086 if (k < 0) {
1087 ifree(pp);
1088 ifree(bp);
1089 return (0);
1091 } else {
1092 bp->size = (1UL << bits);
1093 bp->shift = bits;
1094 bp->total = bp->free = malloc_pagesize >> bits;
1095 bp->page = pp;
1098 /* set all valid bits in the bitmap */
1099 k = bp->total;
1100 i = 0;
1102 /* Do a bunch at a time */
1103 for (; (k - i) >= MALLOC_BITS; i += MALLOC_BITS)
1104 bp->bits[i / MALLOC_BITS] = ~0UL;
1106 for (; i < k; i++)
1107 bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
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);
1119 /* MALLOC_LOCK */
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);
1129 #endif /* MALLOC_EXTRA_SANITY */
1130 if (pi != last_dir) {
1131 prev_dir = last_dir;
1132 last_dir = pi;
1134 pd = pi->base;
1135 pd[PI_OFF(ptr2index(pp))] = bp;
1137 bp->next = page_dir[bits];
1138 page_dir[bits] = bp;
1140 /* MALLOC_UNLOCK */
1141 return (1);
1145 * Allocate a fragment
1147 static void *
1148 malloc_bytes(size_t size)
1150 int i, j;
1151 size_t k;
1152 u_long u, *lp;
1153 struct pginfo *bp;
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;
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++;
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);
1175 bp = page_dir[j];
1177 /* Find first word of bitmap which isn't empty */
1178 for (lp = bp->bits; !*lp; lp++);
1180 /* Find that bit, and tweak it */
1181 u = 1;
1182 k = 0;
1183 while (!(*lp & u)) {
1184 u += u;
1185 k++;
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;
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);
1206 #endif /* MALLOC_EXTRA_SANITY */
1207 if (*lp & u)
1208 i--;
1211 *lp ^= u;
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;
1218 /* Adjust to the real offset of that chunk */
1219 k += (lp - bp->bits) * MALLOC_BITS;
1220 k <<= bp->shift;
1222 if (malloc_junk && bp->size != 0)
1223 memset((char *)bp->page + k, SOME_JUNK, (size_t)bp->size);
1225 return ((u_char *) bp->page + k);
1229 * Magic so that malloc(sizeof(ptr)) is near the end of the page.
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)
1236 * Allocate a piece of memory
1238 static void *
1239 imalloc(size_t size)
1241 void *result;
1242 int ptralloc = 0;
1244 if (!malloc_started)
1245 malloc_init();
1247 if (suicide)
1248 abort();
1250 /* does not matter if malloc_bytes fails */
1251 if (px == NULL)
1252 px = malloc_bytes(sizeof *px);
1254 if (malloc_ptrguard && size == PTR_SIZE) {
1255 ptralloc = 1;
1256 size = malloc_pagesize;
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);
1266 if (malloc_abort == 1 && result == NULL)
1267 wrterror("allocation failed");
1269 if (malloc_zero && result != NULL)
1270 memset(result, 0, size);
1272 if (result && ptralloc)
1273 return ((char *) result + PTR_GAP);
1274 return (result);
1278 * Change the size of an allocation.
1280 static void *
1281 irealloc(void *ptr, size_t size)
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 */
1293 if (suicide)
1294 abort();
1296 if (!malloc_started) {
1297 wrtwarning("malloc() has never been called");
1298 return (NULL);
1300 if (malloc_ptrguard && PTR_ALIGNED(ptr)) {
1301 if (size <= PTR_SIZE)
1302 return (ptr);
1304 p = imalloc(size);
1305 if (p)
1306 memcpy(p, ptr, PTR_SIZE);
1307 ifree(ptr);
1308 return (p);
1310 index = ptr2index(ptr);
1312 if (index < malloc_pageshift) {
1313 wrtwarning("junk pointer, too low to make sense");
1314 return (NULL);
1316 if (index > last_index) {
1317 wrtwarning("junk pointer, too high to make sense");
1318 return (NULL);
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);
1328 #endif /* MALLOC_EXTRA_SANITY */
1329 if (pi != last_dir) {
1330 prev_dir = last_dir;
1331 last_dir = pi;
1333 pd = pi->base;
1334 mp = &pd[PI_OFF(index)];
1336 if (*mp == MALLOC_FIRST) { /* Page allocation */
1338 /* Check the pointer */
1339 if ((u_long) ptr & malloc_pagemask) {
1340 wrtwarning("modified (page-) pointer");
1341 return (NULL);
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;
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;
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. */
1370 } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */
1372 /* Check the pointer for sane values */
1373 if ((u_long) ptr & ((1UL << ((*mp)->shift)) - 1)) {
1374 wrtwarning("modified (chunk-) pointer");
1375 return (NULL);
1377 /* Find the chunk index in the page */
1378 i = ((u_long) ptr & malloc_pagemask) >> (*mp)->shift;
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);
1385 osize = (*mp)->size;
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. */
1393 } else {
1394 wrtwarning("irealloc: pointer to wrong page");
1395 return (NULL);
1398 p = imalloc(size);
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);
1409 ifree(ptr);
1411 return (p);
1415 * Free a sequence of pages
1417 static __inline__ void
1418 free_pages(void *ptr, u_long index, struct pginfo * info)
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;
1427 if (info == MALLOC_FREE) {
1428 wrtwarning("page is already free");
1429 return;
1431 if (info != MALLOC_FIRST) {
1432 wrtwarning("free_pages: pointer to wrong page");
1433 return;
1435 if ((u_long) ptr & malloc_pagemask) {
1436 wrtwarning("modified (page-) pointer");
1437 return;
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;
1448 #endif /* MALLOC_EXTRA_SANITY */
1450 spi = pi; /* Save page index for start of region. */
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;
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;
1474 l = i << malloc_pageshift;
1476 if (malloc_junk)
1477 memset(ptr, SOME_JUNK, l);
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;
1488 #endif /* MALLOC_EXTRA_SANITY */
1489 pd[PI_OFF(index + i)] = MALLOC_FREE;
1490 l += malloc_guard;
1492 tail = (caddr_t)ptr + l;
1494 if (malloc_hint)
1495 madvise(ptr, l, MADV_FREE);
1497 if (malloc_freeprot)
1498 mprotect(ptr, l, PROT_NONE);
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;
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 {
1516 * Find the right spot, leave pf pointing to the modified
1517 * entry.
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;
1527 /* Finish cache size calculation. */
1528 pt = pf;
1529 while (pt) {
1530 cachesize += pt->size;
1531 pt = pt->next;
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;
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;
1575 if (pf->pdir != last_dir) {
1576 prev_dir = last_dir;
1577 last_dir = pf->pdir;
1580 /* Return something to OS ? */
1581 if (pf->size > (malloc_cache - cachesize)) {
1584 * Keep the cache intact. Notice that the '>' above guarantees that
1585 * the pf will always have at least one page afterwards.
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;
1594 index = ptr2index((caddr_t)pf->page + pf->size);
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 ! */
1600 for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
1601 pi = pi->next)
1604 spi = pi;
1605 if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
1606 pd = pi->base;
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;
1617 #endif /* MALLOC_EXTRA_SANITY */
1618 pi->dirnum--;
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)) {
1627 * If no page in that dir, free
1628 * directory page.
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;
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);
1661 if (pi == NULL && malloc_brk == tail) {
1662 /* Resize down the malloc upper boundary. */
1663 last_index = index - 1;
1664 malloc_brk = index2ptr(index);
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;
1693 #else /* !MALLOC_EXTRA_SANITY */
1696 #endif /* MALLOC_EXTRA_SANITY */
1697 malloc_brk = index2ptr(i + 1);
1699 last_index = i;
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;
1707 px = pf;
1708 last_dir = prev_dir;
1709 prev_dir = NULL;
1712 not_return:
1713 if (pt != NULL)
1714 ifree(pt);
1718 * Free a chunk, and possibly the page it's on, if the page becomes empty.
1721 /* ARGSUSED */
1722 static __inline__ void
1723 free_bytes(void *ptr, u_long index, struct pginfo * info)
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;
1734 /* Find the chunk number on the page */
1735 i = ((u_long) ptr & malloc_pagemask) >> info->shift;
1737 if ((u_long) ptr & ((1UL << (info->shift)) - 1)) {
1738 wrtwarning("modified (chunk-) pointer");
1739 return;
1741 if (info->bits[i / MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) {
1742 wrtwarning("chunk is already free");
1743 return;
1745 if (malloc_junk && info->size != 0)
1746 memset(ptr, SOME_JUNK, (size_t)info->size);
1748 info->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS);
1749 info->free++;
1751 if (info->size != 0)
1752 mp = page_dir + info->shift;
1753 else
1754 mp = page_dir;
1756 if (info->free == 1) {
1757 /* Page became non-full */
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;
1767 if (info->free != info->total)
1768 return;
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;
1779 #endif /* MALLOC_EXTRA_SANITY */
1781 *mp = info->next;
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;
1792 #endif /* MALLOC_EXTRA_SANITY */
1793 if (pi != last_dir) {
1794 prev_dir = last_dir;
1795 last_dir = pi;
1797 pd = pi->base;
1798 pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
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);
1804 vp = info->page; /* Order is important ! */
1805 if (vp != (void *) info)
1806 ifree(info);
1807 ifree(vp);
1810 static void
1811 ifree(void *ptr)
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;
1820 if (!malloc_started) {
1821 wrtwarning("malloc() has never been called");
1822 return;
1824 /* If we're already sinking, don't make matters any worse. */
1825 if (suicide)
1826 return;
1828 if (malloc_ptrguard && PTR_ALIGNED(ptr))
1829 ptr = (char *) ptr - PTR_GAP;
1831 index = ptr2index(ptr);
1833 if (index < malloc_pageshift) {
1834 warnx("(%p)", ptr);
1835 wrtwarning("ifree: junk pointer, too low to make sense");
1836 return;
1838 if (index > last_index) {
1839 warnx("(%p)", ptr);
1840 wrtwarning("ifree: junk pointer, too high to make sense");
1841 return;
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;
1851 #endif /* MALLOC_EXTRA_SANITY */
1852 if (pi != last_dir) {
1853 prev_dir = last_dir;
1854 last_dir = pi;
1856 pd = pi->base;
1857 info = pd[PI_OFF(index)];
1859 if (info < MALLOC_MAGIC)
1860 free_pages(ptr, index, info);
1861 else
1862 free_bytes(ptr, index, info);
1864 /* does not matter if malloc_bytes fails */
1865 if (px == NULL)
1866 px = malloc_bytes(sizeof *px);
1868 return;
1872 * Common function for handling recursion. Only
1873 * print the error message once, to avoid making the problem
1874 * potentially worse.
1876 static void
1877 malloc_recurse(void)
1879 static int noprint;
1881 if (noprint == 0) {
1882 noprint = 1;
1883 wrtwarning("recursive call");
1885 malloc_active--;
1886 _MALLOC_UNLOCK();
1887 errno = EDEADLK;
1891 * These are the public exported interface routines.
1893 void *
1894 malloc(size_t size)
1896 void *r;
1898 if (!align)
1899 _MALLOC_LOCK();
1900 malloc_func = " in malloc():";
1901 if (malloc_active++) {
1902 malloc_recurse();
1903 return (NULL);
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;
1914 return (r);
1917 void
1918 free(void *ptr)
1920 /* This is legal. XXX quick path */
1921 if (ptr == NULL)
1922 return;
1924 _MALLOC_LOCK();
1925 malloc_func = " in free():";
1926 if (malloc_active++) {
1927 malloc_recurse();
1928 return;
1930 ifree(ptr);
1931 UTRACE(ptr, 0, 0);
1932 malloc_active--;
1933 _MALLOC_UNLOCK();
1934 return;
1937 void *
1938 realloc(void *ptr, size_t size)
1940 void *r;
1942 _MALLOC_LOCK();
1943 malloc_func = " in realloc():";
1944 if (malloc_active++) {
1945 malloc_recurse();
1946 return (NULL);
1949 if (ptr == NULL)
1950 r = imalloc(size);
1951 else
1952 r = irealloc(ptr, size);
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;
1961 return (r);
1964 void *
1965 calloc(size_t num, size_t size)
1967 void *p;
1969 if (num && SIZE_MAX / num < size) {
1970 fprintf(stderr,"OOOOPS");
1971 errno = ENOMEM;
1972 return NULL;
1974 size *= num;
1975 p = malloc(size);
1976 if (p)
1977 memset(p, 0, size);
1978 return(p);
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;
1989 #endif
1991 #ifndef BUILDING_FOR_TOR
1992 int posix_memalign(void **memptr, size_t alignment, size_t size)
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();
2010 *memptr = r;
2011 if (!r) return ENOMEM;
2012 return 0;
2015 void *memalign(size_t boundary, size_t size)
2017 void *r;
2018 posix_memalign(&r, boundary, size);
2019 return r;
2022 void *valloc(size_t size)
2024 void *r;
2025 posix_memalign(&r, malloc_pagesize, size);
2026 return r;
2028 #endif
2030 size_t malloc_good_size(size_t size)
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);