1 /* $NetBSD: malloc.c,v 1.52 2008/02/03 22:56:53 christos Exp $ */ 2 3 /* 4 * ---------------------------------------------------------------------------- 5 * "THE BEER-WARE LICENSE" (Revision 42): 6 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 7 * can do whatever you want with this stuff. If we meet some day, and you think 8 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 9 * ---------------------------------------------------------------------------- 10 * 11 * From FreeBSD: malloc.c,v 1.91 2006/01/12 07:28:20 jasone 12 * 13 */ 14 15 #ifdef __minix 16 #define mmap minix_mmap 17 #define munmap minix_munmap 18 #endif 19 20 /* 21 * Defining MALLOC_EXTRA_SANITY will enable extra checks which are related 22 * to internal conditions and consistency in malloc.c. This has a 23 * noticeable runtime performance hit, and generally will not do you 24 * any good unless you fiddle with the internals of malloc or want 25 * to catch random pointer corruption as early as possible. 26 */ 27 #ifndef MALLOC_EXTRA_SANITY 28 #undef MALLOC_EXTRA_SANITY 29 #endif 30 31 /* 32 * What to use for Junk. This is the byte value we use to fill with 33 * when the 'J' option is enabled. 34 */ 35 #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ 36 37 /* 38 * The basic parameters you can tweak. 39 * 40 * malloc_minsize minimum size of an allocation in bytes. 41 * If this is too small it's too much work 42 * to manage them. This is also the smallest 43 * unit of alignment used for the storage 44 * returned by malloc/realloc. 45 * 46 */ 47 48 #include "namespace.h" 49 #if defined(__FreeBSD__) 50 # if defined(__i386__) 51 # define malloc_minsize 16U 52 # endif 53 # if defined(__ia64__) 54 # define malloc_pageshift 13U 55 # define malloc_minsize 16U 56 # endif 57 # if defined(__alpha__) 58 # define malloc_pageshift 13U 59 # define malloc_minsize 16U 60 # endif 61 # if defined(__sparc64__) 62 # define malloc_pageshift 13U 63 # define malloc_minsize 16U 64 # endif 65 # if defined(__amd64__) 66 # define malloc_pageshift 12U 67 # define malloc_minsize 16U 68 # endif 69 # if defined(__arm__) 70 # define malloc_pageshift 12U 71 # define malloc_minsize 16U 72 # endif 73 #ifndef __minix 74 # define HAS_UTRACE 75 # define UTRACE_LABEL 76 #endif /* __minix */ 77 78 #include <sys/cdefs.h> 79 void utrace(struct ut *, int); 80 81 /* 82 * Make malloc/free/realloc thread-safe in libc for use with 83 * kernel threads. 84 */ 85 # include "libc_private.h" 86 # include "spinlock.h" 87 static spinlock_t thread_lock = _SPINLOCK_INITIALIZER; 88 # define _MALLOC_LOCK() if (__isthreaded) _SPINLOCK(&thread_lock); 89 # define _MALLOC_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock); 90 #endif /* __FreeBSD__ */ 91 92 #include <sys/types.h> 93 #if defined(__NetBSD__) 94 # define malloc_minsize 16U 95 # define HAS_UTRACE 96 # define UTRACE_LABEL "malloc", 97 #include <sys/cdefs.h> 98 #include "extern.h" 99 #if defined(LIBC_SCCS) && !defined(lint) 100 __RCSID("$NetBSD: malloc.c,v 1.52 2008/02/03 22:56:53 christos Exp $"); 101 #endif /* LIBC_SCCS and not lint */ 102 int utrace(const char *, void *, size_t); 103 104 #include <reentrant.h> 105 extern int __isthreaded; 106 static mutex_t thread_lock = MUTEX_INITIALIZER; 107 #define _MALLOC_LOCK() if (__isthreaded) mutex_lock(&thread_lock); 108 #define _MALLOC_UNLOCK() if (__isthreaded) mutex_unlock(&thread_lock); 109 #endif /* __NetBSD__ */ 110 111 #if defined(__sparc__) && defined(sun) 112 # define malloc_minsize 16U 113 # define MAP_ANON (0) 114 static int fdzero; 115 # define MMAP_FD fdzero 116 # define INIT_MMAP() \ 117 { if ((fdzero = open(_PATH_DEVZERO, O_RDWR, 0000)) == -1) \ 118 wrterror("open of /dev/zero"); } 119 #endif /* __sparc__ */ 120 121 /* Insert your combination here... */ 122 #if defined(__FOOCPU__) && defined(__BAROS__) 123 # define malloc_minsize 16U 124 #endif /* __FOOCPU__ && __BAROS__ */ 125 126 #ifndef ZEROSIZEPTR 127 #define ZEROSIZEPTR ((void *)(uintptr_t)(1UL << (malloc_pageshift - 1))) 128 #endif 129 130 /* 131 * No user serviceable parts behind this point. 132 */ 133 #include <sys/types.h> 134 #include <sys/mman.h> 135 #include <errno.h> 136 #include <fcntl.h> 137 #include <paths.h> 138 #include <stddef.h> 139 #include <stdio.h> 140 #include <stdlib.h> 141 #include <string.h> 142 #include <unistd.h> 143 144 /* 145 * This structure describes a page worth of chunks. 146 */ 147 148 struct pginfo { 149 struct pginfo *next; /* next on the free list */ 150 void *page; /* Pointer to the page */ 151 u_short size; /* size of this page's chunks */ 152 u_short shift; /* How far to shift for this size chunks */ 153 u_short free; /* How many free chunks */ 154 u_short total; /* How many chunk */ 155 u_int bits[1]; /* Which chunks are free */ 156 }; 157 158 /* 159 * This structure describes a number of free pages. 160 */ 161 162 struct pgfree { 163 struct pgfree *next; /* next run of free pages */ 164 struct pgfree *prev; /* prev run of free pages */ 165 void *page; /* pointer to free pages */ 166 void *end; /* pointer to end of free pages */ 167 size_t size; /* number of bytes free */ 168 }; 169 170 /* 171 * How many bits per u_int in the bitmap. 172 * Change only if not 8 bits/byte 173 */ 174 #define MALLOC_BITS ((int)(8*sizeof(u_int))) 175 176 /* 177 * Magic values to put in the page_directory 178 */ 179 #define MALLOC_NOT_MINE ((struct pginfo*) 0) 180 #define MALLOC_FREE ((struct pginfo*) 1) 181 #define MALLOC_FIRST ((struct pginfo*) 2) 182 #define MALLOC_FOLLOW ((struct pginfo*) 3) 183 #define MALLOC_MAGIC ((struct pginfo*) 4) 184 185 /* 186 * Page size related parameters, computed at run-time. 187 */ 188 static size_t malloc_pagesize; 189 static size_t malloc_pageshift; 190 static size_t malloc_pagemask; 191 192 #ifndef malloc_minsize 193 #define malloc_minsize 16U 194 #endif 195 196 #ifndef malloc_maxsize 197 #define malloc_maxsize ((malloc_pagesize)>>1) 198 #endif 199 200 #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) 201 #define ptr2idx(foo) \ 202 (((size_t)(uintptr_t)(foo) >> malloc_pageshift)-malloc_origo) 203 204 #ifndef _MALLOC_LOCK 205 #define _MALLOC_LOCK() 206 #endif 207 208 #ifndef _MALLOC_UNLOCK 209 #define _MALLOC_UNLOCK() 210 #endif 211 212 #ifndef MMAP_FD 213 #define MMAP_FD (-1) 214 #endif 215 216 #ifndef INIT_MMAP 217 #define INIT_MMAP() 218 #endif 219 220 #ifndef __minix 221 #ifndef MADV_FREE 222 #define MADV_FREE MADV_DONTNEED 223 #endif 224 #endif /* !__minix */ 225 226 /* Number of free pages we cache */ 227 static size_t malloc_cache = 16; 228 229 /* The offset from pagenumber to index into the page directory */ 230 static size_t malloc_origo; 231 232 /* The last index in the page directory we care about */ 233 static size_t last_idx; 234 235 /* Pointer to page directory. Allocated "as if with" malloc */ 236 static struct pginfo **page_dir; 237 238 /* How many slots in the page directory */ 239 static size_t malloc_ninfo; 240 241 /* Free pages line up here */ 242 static struct pgfree free_list; 243 244 /* Abort(), user doesn't handle problems. */ 245 static int malloc_abort; 246 247 /* Are we trying to die ? */ 248 static int suicide; 249 250 /* always realloc ? */ 251 static int malloc_realloc; 252 253 /* pass the kernel a hint on free pages ? */ 254 #if defined(MADV_FREE) 255 static int malloc_hint = 0; 256 #endif 257 258 /* xmalloc behaviour ? */ 259 static int malloc_xmalloc; 260 261 /* sysv behaviour for malloc(0) ? */ 262 static int malloc_sysv; 263 264 /* zero fill ? */ 265 static int malloc_zero; 266 267 /* junk fill ? */ 268 static int malloc_junk; 269 270 #ifdef HAS_UTRACE 271 272 /* utrace ? */ 273 static int malloc_utrace; 274 275 struct ut { void *p; size_t s; void *r; }; 276 277 #define UTRACE(a, b, c) \ 278 if (malloc_utrace) { \ 279 struct ut u; \ 280 u.p=a; u.s = b; u.r=c; \ 281 utrace(UTRACE_LABEL (void *) &u, sizeof u); \ 282 } 283 #else /* !HAS_UTRACE */ 284 #define UTRACE(a,b,c) 285 #endif /* HAS_UTRACE */ 286 287 /* my last break. */ 288 static void *malloc_brk; 289 290 /* one location cache for free-list holders */ 291 static struct pgfree *px; 292 293 /* compile-time options */ 294 const char *_malloc_options; 295 296 /* Name of the current public function */ 297 static const char *malloc_func; 298 299 /* Macro for mmap */ 300 #define MMAP(size) \ 301 mmap(NULL, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ 302 MMAP_FD, (off_t)0); 303 304 /* 305 * Necessary function declarations 306 */ 307 static int extend_pgdir(size_t idx); 308 static void *imalloc(size_t size); 309 static void ifree(void *ptr); 310 static void *irealloc(void *ptr, size_t size); 311 312 static void 313 wrtmessage(const char *p1, const char *p2, const char *p3, const char *p4) 314 { 315 316 write(STDERR_FILENO, p1, strlen(p1)); 317 write(STDERR_FILENO, p2, strlen(p2)); 318 write(STDERR_FILENO, p3, strlen(p3)); 319 write(STDERR_FILENO, p4, strlen(p4)); 320 } 321 322 void (*_malloc_message)(const char *p1, const char *p2, const char *p3, 323 const char *p4) = wrtmessage; 324 static void 325 wrterror(const char *p) 326 { 327 328 suicide = 1; 329 _malloc_message(getprogname(), malloc_func, " error: ", p); 330 abort(); 331 } 332 333 static void 334 wrtwarning(const char *p) 335 { 336 337 /* 338 * Sensitive processes, somewhat arbitrarily defined here as setuid, 339 * setgid, root and wheel cannot afford to have malloc mistakes. 340 */ 341 if (malloc_abort || issetugid() || getuid() == 0 || getgid() == 0) 342 wrterror(p); 343 } 344 345 /* 346 * Allocate a number of pages from the OS 347 */ 348 static void * 349 map_pages(size_t pages) 350 { 351 caddr_t result, rresult, tail; 352 intptr_t bytes = pages << malloc_pageshift; 353 354 if (bytes < 0 || (size_t)bytes < pages) { 355 errno = ENOMEM; 356 return NULL; 357 } 358 359 if ((result = sbrk(bytes)) == (void *)-1) 360 return NULL; 361 362 /* 363 * Round to a page, in case sbrk(2) did not do this for us 364 */ 365 rresult = (caddr_t)pageround((size_t)(uintptr_t)result); 366 if (result < rresult) { 367 /* make sure we have enough space to fit bytes */ 368 if (sbrk((intptr_t)(rresult - result)) == (void *) -1) { 369 /* we failed, put everything back */ 370 if (brk(result)) { 371 wrterror("brk(2) failed [internal error]\n"); 372 } 373 } 374 } 375 tail = rresult + (size_t)bytes; 376 377 last_idx = ptr2idx(tail) - 1; 378 malloc_brk = tail; 379 380 if ((last_idx+1) >= malloc_ninfo && !extend_pgdir(last_idx)) { 381 malloc_brk = result; 382 last_idx = ptr2idx(malloc_brk) - 1; 383 /* Put back break point since we failed. */ 384 if (brk(malloc_brk)) 385 wrterror("brk(2) failed [internal error]\n"); 386 return 0; 387 } 388 389 return rresult; 390 } 391 392 /* 393 * Extend page directory 394 */ 395 static int 396 extend_pgdir(size_t idx) 397 { 398 struct pginfo **new, **old; 399 size_t newlen, oldlen; 400 401 /* check for overflow */ 402 if ((((~(1UL << ((sizeof(size_t) * NBBY) - 1)) / sizeof(*page_dir)) + 1) 403 + (malloc_pagesize / sizeof *page_dir)) < idx) { 404 errno = ENOMEM; 405 return 0; 406 } 407 408 /* Make it this many pages */ 409 newlen = pageround(idx * sizeof *page_dir) + malloc_pagesize; 410 411 /* remember the old mapping size */ 412 oldlen = malloc_ninfo * sizeof *page_dir; 413 414 /* 415 * NOTE: we allocate new pages and copy the directory rather than tempt 416 * fate by trying to "grow" the region.. There is nothing to prevent 417 * us from accidentally re-mapping space that's been allocated by our caller 418 * via dlopen() or other mmap(). 419 * 420 * The copy problem is not too bad, as there is 4K of page index per 421 * 4MB of malloc arena. 422 * 423 * We can totally avoid the copy if we open a file descriptor to associate 424 * the anon mappings with. Then, when we remap the pages at the new 425 * address, the old pages will be "magically" remapped.. But this means 426 * keeping open a "secret" file descriptor..... 427 */ 428 429 /* Get new pages */ 430 new = MMAP(newlen); 431 if (new == MAP_FAILED) 432 return 0; 433 434 /* Copy the old stuff */ 435 memcpy(new, page_dir, oldlen); 436 437 /* register the new size */ 438 malloc_ninfo = newlen / sizeof *page_dir; 439 440 /* swap the pointers */ 441 old = page_dir; 442 page_dir = new; 443 444 /* Now free the old stuff */ 445 munmap(old, oldlen); 446 return 1; 447 } 448 449 /* 450 * Initialize the world 451 */ 452 static void 453 malloc_init(void) 454 { 455 const char *p; 456 char b[64]; 457 size_t i; 458 ssize_t j; 459 int save_errno = errno; 460 461 /* 462 * Compute page-size related variables. 463 */ 464 malloc_pagesize = (size_t)sysconf(_SC_PAGESIZE); 465 malloc_pagemask = malloc_pagesize - 1; 466 for (malloc_pageshift = 0; 467 (1UL << malloc_pageshift) != malloc_pagesize; 468 malloc_pageshift++) 469 /* nothing */ ; 470 471 INIT_MMAP(); 472 473 #ifdef MALLOC_EXTRA_SANITY 474 malloc_junk = 1; 475 #endif /* MALLOC_EXTRA_SANITY */ 476 477 for (i = 0; i < 3; i++) { 478 if (i == 0) { 479 j = readlink("/etc/malloc.conf", b, sizeof b - 1); 480 if (j <= 0) 481 continue; 482 b[j] = '\0'; 483 p = b; 484 } else if (i == 1 && issetugid() == 0) { 485 p = getenv("MALLOC_OPTIONS"); 486 } else if (i == 1) { 487 continue; 488 } else { 489 p = _malloc_options; 490 } 491 for (; p != NULL && *p != '\0'; p++) { 492 switch (*p) { 493 case '>': malloc_cache <<= 1; break; 494 case '<': malloc_cache >>= 1; break; 495 case 'a': malloc_abort = 0; break; 496 case 'A': malloc_abort = 1; break; 497 #ifndef __minix 498 case 'h': malloc_hint = 0; break; 499 case 'H': malloc_hint = 1; break; 500 #endif /* !__minix */ 501 case 'r': malloc_realloc = 0; break; 502 case 'R': malloc_realloc = 1; break; 503 case 'j': malloc_junk = 0; break; 504 case 'J': malloc_junk = 1; break; 505 #ifdef HAS_UTRACE 506 case 'u': malloc_utrace = 0; break; 507 case 'U': malloc_utrace = 1; break; 508 #endif 509 case 'v': malloc_sysv = 0; break; 510 case 'V': malloc_sysv = 1; break; 511 case 'x': malloc_xmalloc = 0; break; 512 case 'X': malloc_xmalloc = 1; break; 513 case 'z': malloc_zero = 0; break; 514 case 'Z': malloc_zero = 1; break; 515 default: 516 _malloc_message(getprogname(), malloc_func, 517 " warning: ", "unknown char in MALLOC_OPTIONS\n"); 518 break; 519 } 520 } 521 } 522 523 UTRACE(0, 0, 0); 524 525 /* 526 * We want junk in the entire allocation, and zero only in the part 527 * the user asked for. 528 */ 529 if (malloc_zero) 530 malloc_junk = 1; 531 532 /* Allocate one page for the page directory */ 533 page_dir = MMAP(malloc_pagesize); 534 535 if (page_dir == MAP_FAILED) 536 wrterror("mmap(2) failed, check limits.\n"); 537 538 /* 539 * We need a maximum of malloc_pageshift buckets, steal these from the 540 * front of the page_directory; 541 */ 542 malloc_origo = pageround((size_t)(uintptr_t)sbrk((intptr_t)0)) 543 >> malloc_pageshift; 544 malloc_origo -= malloc_pageshift; 545 546 malloc_ninfo = malloc_pagesize / sizeof *page_dir; 547 548 /* Recalculate the cache size in bytes, and make sure it's nonzero */ 549 550 if (!malloc_cache) 551 malloc_cache++; 552 553 malloc_cache <<= malloc_pageshift; 554 555 /* 556 * This is a nice hack from Kaleb Keithly (kaleb@x.org). 557 * We can sbrk(2) further back when we keep this on a low address. 558 */ 559 px = imalloc(sizeof *px); 560 561 errno = save_errno; 562 } 563 564 /* 565 * Allocate a number of complete pages 566 */ 567 static void * 568 malloc_pages(size_t size) 569 { 570 void *p, *delay_free = NULL; 571 size_t i; 572 struct pgfree *pf; 573 size_t idx; 574 575 idx = pageround(size); 576 if (idx < size) { 577 errno = ENOMEM; 578 return NULL; 579 } else 580 size = idx; 581 582 p = NULL; 583 584 /* Look for free pages before asking for more */ 585 for(pf = free_list.next; pf; pf = pf->next) { 586 587 #ifdef MALLOC_EXTRA_SANITY 588 if (pf->size & malloc_pagemask) 589 wrterror("(ES): junk length entry on free_list.\n"); 590 if (!pf->size) 591 wrterror("(ES): zero length entry on free_list.\n"); 592 if (pf->page == pf->end) 593 wrterror("(ES): zero entry on free_list.\n"); 594 if (pf->page > pf->end) 595 wrterror("(ES): sick entry on free_list.\n"); 596 if ((void*)pf->page >= (void*)sbrk(0)) 597 wrterror("(ES): entry on free_list past brk.\n"); 598 if (page_dir[ptr2idx(pf->page)] != MALLOC_FREE) 599 wrterror("(ES): non-free first page on free-list.\n"); 600 if (page_dir[ptr2idx(pf->end)-1] != MALLOC_FREE) 601 wrterror("(ES): non-free last page on free-list.\n"); 602 #endif /* MALLOC_EXTRA_SANITY */ 603 604 if (pf->size < size) 605 continue; 606 607 if (pf->size == size) { 608 p = pf->page; 609 if (pf->next != NULL) 610 pf->next->prev = pf->prev; 611 pf->prev->next = pf->next; 612 delay_free = pf; 613 break; 614 } 615 616 p = pf->page; 617 pf->page = (char *)pf->page + size; 618 pf->size -= size; 619 break; 620 } 621 622 #ifdef MALLOC_EXTRA_SANITY 623 if (p != NULL && page_dir[ptr2idx(p)] != MALLOC_FREE) 624 wrterror("(ES): allocated non-free page on free-list.\n"); 625 #endif /* MALLOC_EXTRA_SANITY */ 626 627 size >>= malloc_pageshift; 628 629 /* Map new pages */ 630 if (p == NULL) 631 p = map_pages(size); 632 633 if (p != NULL) { 634 635 idx = ptr2idx(p); 636 page_dir[idx] = MALLOC_FIRST; 637 for (i=1;i<size;i++) 638 page_dir[idx+i] = MALLOC_FOLLOW; 639 640 if (malloc_junk) 641 memset(p, SOME_JUNK, size << malloc_pageshift); 642 } 643 644 if (delay_free) { 645 if (px == NULL) 646 px = delay_free; 647 else 648 ifree(delay_free); 649 } 650 651 return p; 652 } 653 654 /* 655 * Allocate a page of fragments 656 */ 657 658 static inline int 659 malloc_make_chunks(int bits) 660 { 661 struct pginfo *bp; 662 void *pp; 663 int i, k; 664 long l; 665 666 /* Allocate a new bucket */ 667 pp = malloc_pages(malloc_pagesize); 668 if (pp == NULL) 669 return 0; 670 671 /* Find length of admin structure */ 672 l = (long)offsetof(struct pginfo, bits[0]); 673 l += (long)sizeof bp->bits[0] * 674 (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS); 675 676 /* Don't waste more than two chunks on this */ 677 if ((1<<(bits)) <= l+l) { 678 bp = (struct pginfo *)pp; 679 } else { 680 bp = imalloc((size_t)l); 681 if (bp == NULL) { 682 ifree(pp); 683 return 0; 684 } 685 } 686 687 bp->size = (1<<bits); 688 bp->shift = bits; 689 bp->total = bp->free = (u_short)(malloc_pagesize >> bits); 690 bp->page = pp; 691 692 /* set all valid bits in the bitmap */ 693 k = bp->total; 694 i = 0; 695 696 /* Do a bunch at a time */ 697 for(;k-i >= MALLOC_BITS; i += MALLOC_BITS) 698 bp->bits[i / MALLOC_BITS] = ~0U; 699 700 for(; i < k; i++) 701 bp->bits[i/MALLOC_BITS] |= 1<<(i%MALLOC_BITS); 702 703 if (bp == bp->page) { 704 /* Mark the ones we stole for ourselves */ 705 for(i = 0; l > 0; i++) { 706 bp->bits[i / MALLOC_BITS] &= ~(1 << (i % MALLOC_BITS)); 707 bp->free--; 708 bp->total--; 709 l -= (long)(1 << bits); 710 } 711 } 712 713 /* MALLOC_LOCK */ 714 715 page_dir[ptr2idx(pp)] = bp; 716 717 bp->next = page_dir[bits]; 718 page_dir[bits] = bp; 719 720 /* MALLOC_UNLOCK */ 721 722 return 1; 723 } 724 725 /* 726 * Allocate a fragment 727 */ 728 static void * 729 malloc_bytes(size_t size) 730 { 731 size_t i; 732 int j; 733 u_int u; 734 struct pginfo *bp; 735 size_t k; 736 u_int *lp; 737 738 /* Don't bother with anything less than this */ 739 if (size < malloc_minsize) 740 size = malloc_minsize; 741 742 743 /* Find the right bucket */ 744 j = 1; 745 i = size-1; 746 while (i >>= 1) 747 j++; 748 749 /* If it's empty, make a page more of that size chunks */ 750 if (page_dir[j] == NULL && !malloc_make_chunks(j)) 751 return NULL; 752 753 bp = page_dir[j]; 754 755 /* Find first word of bitmap which isn't empty */ 756 for (lp = bp->bits; !*lp; lp++) 757 ; 758 759 /* Find that bit, and tweak it */ 760 u = 1; 761 k = 0; 762 while (!(*lp & u)) { 763 u += u; 764 k++; 765 } 766 *lp ^= u; 767 768 /* If there are no more free, remove from free-list */ 769 if (!--bp->free) { 770 page_dir[j] = bp->next; 771 bp->next = NULL; 772 } 773 774 /* Adjust to the real offset of that chunk */ 775 k += (lp-bp->bits)*MALLOC_BITS; 776 k <<= bp->shift; 777 778 if (malloc_junk) 779 memset((u_char*)bp->page + k, SOME_JUNK, (size_t)bp->size); 780 781 return (u_char *)bp->page + k; 782 } 783 784 /* 785 * Allocate a piece of memory 786 */ 787 static void * 788 imalloc(size_t size) 789 { 790 void *result; 791 792 if (suicide) 793 abort(); 794 795 if ((size + malloc_pagesize) < size) /* Check for overflow */ 796 result = NULL; 797 else if ((size + malloc_pagesize) >= (uintptr_t)page_dir) 798 result = NULL; 799 else if (size <= malloc_maxsize) 800 result = malloc_bytes(size); 801 else 802 result = malloc_pages(size); 803 804 if (malloc_abort && result == NULL) 805 wrterror("allocation failed.\n"); 806 807 if (malloc_zero && result != NULL) 808 memset(result, 0, size); 809 810 return result; 811 } 812 813 /* 814 * Change the size of an allocation. 815 */ 816 static void * 817 irealloc(void *ptr, size_t size) 818 { 819 void *p; 820 size_t osize, idx; 821 struct pginfo **mp; 822 size_t i; 823 824 if (suicide) 825 abort(); 826 827 idx = ptr2idx(ptr); 828 829 if (idx < malloc_pageshift) { 830 wrtwarning("junk pointer, too low to make sense.\n"); 831 return 0; 832 } 833 834 if (idx > last_idx) { 835 wrtwarning("junk pointer, too high to make sense.\n"); 836 return 0; 837 } 838 839 mp = &page_dir[idx]; 840 841 if (*mp == MALLOC_FIRST) { /* Page allocation */ 842 843 /* Check the pointer */ 844 if ((size_t)(uintptr_t)ptr & malloc_pagemask) { 845 wrtwarning("modified (page-) pointer.\n"); 846 return NULL; 847 } 848 849 /* Find the size in bytes */ 850 for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;) 851 osize += malloc_pagesize; 852 853 if (!malloc_realloc && /* unless we have to, */ 854 size <= osize && /* .. or are too small, */ 855 size > (osize - malloc_pagesize)) { /* .. or can free a page, */ 856 if (malloc_junk) 857 memset((u_char *)ptr + size, SOME_JUNK, osize-size); 858 return ptr; /* don't do anything. */ 859 } 860 861 } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */ 862 863 /* Check the pointer for sane values */ 864 if (((size_t)(uintptr_t)ptr & ((*mp)->size-1))) { 865 wrtwarning("modified (chunk-) pointer.\n"); 866 return NULL; 867 } 868 869 /* Find the chunk index in the page */ 870 i = ((size_t)(uintptr_t)ptr & malloc_pagemask) >> (*mp)->shift; 871 872 /* Verify that it isn't a free chunk already */ 873 if ((*mp)->bits[i/MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) { 874 wrtwarning("chunk is already free.\n"); 875 return NULL; 876 } 877 878 osize = (*mp)->size; 879 880 if (!malloc_realloc && /* Unless we have to, */ 881 size <= osize && /* ..or are too small, */ 882 (size > osize / 2 || /* ..or could use a smaller size, */ 883 osize == malloc_minsize)) { /* ..(if there is one) */ 884 if (malloc_junk) 885 memset((u_char *)ptr + size, SOME_JUNK, osize-size); 886 return ptr; /* ..Don't do anything */ 887 } 888 889 } else { 890 wrtwarning("pointer to wrong page.\n"); 891 return NULL; 892 } 893 894 p = imalloc(size); 895 896 if (p != NULL) { 897 /* copy the lesser of the two sizes, and free the old one */ 898 if (!size || !osize) 899 ; 900 else if (osize < size) 901 memcpy(p, ptr, osize); 902 else 903 memcpy(p, ptr, size); 904 ifree(ptr); 905 } 906 return p; 907 } 908 909 /* 910 * Free a sequence of pages 911 */ 912 913 static inline void 914 free_pages(void *ptr, size_t idx, struct pginfo *info) 915 { 916 size_t i; 917 struct pgfree *pf, *pt=NULL; 918 size_t l; 919 void *tail; 920 921 if (info == MALLOC_FREE) { 922 wrtwarning("page is already free.\n"); 923 return; 924 } 925 926 if (info != MALLOC_FIRST) { 927 wrtwarning("pointer to wrong page.\n"); 928 return; 929 } 930 931 if ((size_t)(uintptr_t)ptr & malloc_pagemask) { 932 wrtwarning("modified (page-) pointer.\n"); 933 return; 934 } 935 936 /* Count how many pages and mark them free at the same time */ 937 page_dir[idx] = MALLOC_FREE; 938 for (i = 1; page_dir[idx+i] == MALLOC_FOLLOW; i++) 939 page_dir[idx + i] = MALLOC_FREE; 940 941 l = i << malloc_pageshift; 942 943 if (malloc_junk) 944 memset(ptr, SOME_JUNK, l); 945 946 #ifndef __minix 947 if (malloc_hint) 948 madvise(ptr, l, MADV_FREE); 949 #endif /* !__minix */ 950 951 tail = (char *)ptr+l; 952 953 /* add to free-list */ 954 if (px == NULL) 955 px = imalloc(sizeof *px); /* This cannot fail... */ 956 px->page = ptr; 957 px->end = tail; 958 px->size = l; 959 if (free_list.next == NULL) { 960 961 /* Nothing on free list, put this at head */ 962 px->next = free_list.next; 963 px->prev = &free_list; 964 free_list.next = px; 965 pf = px; 966 px = NULL; 967 968 } else { 969 970 /* Find the right spot, leave pf pointing to the modified entry. */ 971 tail = (char *)ptr+l; 972 973 for(pf = free_list.next; pf->end < ptr && pf->next != NULL; 974 pf = pf->next) 975 ; /* Race ahead here */ 976 977 if (pf->page > tail) { 978 /* Insert before entry */ 979 px->next = pf; 980 px->prev = pf->prev; 981 pf->prev = px; 982 px->prev->next = px; 983 pf = px; 984 px = NULL; 985 } else if (pf->end == ptr ) { 986 /* Append to the previous entry */ 987 pf->end = (char *)pf->end + l; 988 pf->size += l; 989 if (pf->next != NULL && pf->end == pf->next->page ) { 990 /* And collapse the next too. */ 991 pt = pf->next; 992 pf->end = pt->end; 993 pf->size += pt->size; 994 pf->next = pt->next; 995 if (pf->next != NULL) 996 pf->next->prev = pf; 997 } 998 } else if (pf->page == tail) { 999 /* Prepend to entry */ 1000 pf->size += l; 1001 pf->page = ptr; 1002 } else if (pf->next == NULL) { 1003 /* Append at tail of chain */ 1004 px->next = NULL; 1005 px->prev = pf; 1006 pf->next = px; 1007 pf = px; 1008 px = NULL; 1009 } else { 1010 wrterror("freelist is destroyed.\n"); 1011 } 1012 } 1013 1014 /* Return something to OS ? */ 1015 if (pf->next == NULL && /* If we're the last one, */ 1016 pf->size > malloc_cache && /* ..and the cache is full, */ 1017 pf->end == malloc_brk && /* ..and none behind us, */ 1018 malloc_brk == sbrk((intptr_t)0)) { /* ..and it's OK to do... */ 1019 1020 /* 1021 * Keep the cache intact. Notice that the '>' above guarantees that 1022 * the pf will always have at least one page afterwards. 1023 */ 1024 pf->end = (char *)pf->page + malloc_cache; 1025 pf->size = malloc_cache; 1026 1027 brk(pf->end); 1028 malloc_brk = pf->end; 1029 1030 idx = ptr2idx(pf->end); 1031 1032 for(i=idx;i <= last_idx;) 1033 page_dir[i++] = MALLOC_NOT_MINE; 1034 1035 last_idx = idx - 1; 1036 1037 /* XXX: We could realloc/shrink the pagedir here I guess. */ 1038 } 1039 if (pt != NULL) 1040 ifree(pt); 1041 } 1042 1043 /* 1044 * Free a chunk, and possibly the page it's on, if the page becomes empty. 1045 */ 1046 1047 static inline void 1048 free_bytes(void *ptr, size_t idx, struct pginfo *info) 1049 { 1050 size_t i; 1051 struct pginfo **mp; 1052 void *vp; 1053 1054 /* Find the chunk number on the page */ 1055 i = ((size_t)(uintptr_t)ptr & malloc_pagemask) >> info->shift; 1056 1057 if (((size_t)(uintptr_t)ptr & (info->size-1))) { 1058 wrtwarning("modified (chunk-) pointer.\n"); 1059 return; 1060 } 1061 1062 if (info->bits[i/MALLOC_BITS] & (1UL << (i % MALLOC_BITS))) { 1063 wrtwarning("chunk is already free.\n"); 1064 return; 1065 } 1066 1067 if (malloc_junk) 1068 memset(ptr, SOME_JUNK, (size_t)info->size); 1069 1070 info->bits[i/MALLOC_BITS] |= (u_int)(1UL << (i % MALLOC_BITS)); 1071 info->free++; 1072 1073 mp = page_dir + info->shift; 1074 1075 if (info->free == 1) { 1076 1077 /* Page became non-full */ 1078 1079 mp = page_dir + info->shift; 1080 /* Insert in address order */ 1081 while (*mp && (*mp)->next && (*mp)->next->page < info->page) 1082 mp = &(*mp)->next; 1083 info->next = *mp; 1084 *mp = info; 1085 return; 1086 } 1087 1088 if (info->free != info->total) 1089 return; 1090 1091 /* Find & remove this page in the queue */ 1092 while (*mp != info) { 1093 mp = &((*mp)->next); 1094 #ifdef MALLOC_EXTRA_SANITY 1095 if (!*mp) 1096 wrterror("(ES): Not on queue.\n"); 1097 #endif /* MALLOC_EXTRA_SANITY */ 1098 } 1099 *mp = info->next; 1100 1101 /* Free the page & the info structure if need be */ 1102 page_dir[idx] = MALLOC_FIRST; 1103 vp = info->page; /* Order is important ! */ 1104 if(vp != (void*)info) 1105 ifree(info); 1106 ifree(vp); 1107 } 1108 1109 static void 1110 ifree(void *ptr) 1111 { 1112 struct pginfo *info; 1113 size_t idx; 1114 1115 /* This is legal */ 1116 if (ptr == NULL) 1117 return; 1118 1119 /* If we're already sinking, don't make matters any worse. */ 1120 if (suicide) 1121 return; 1122 1123 idx = ptr2idx(ptr); 1124 1125 if (idx < malloc_pageshift) { 1126 wrtwarning("junk pointer, too low to make sense.\n"); 1127 return; 1128 } 1129 1130 if (idx > last_idx) { 1131 wrtwarning("junk pointer, too high to make sense.\n"); 1132 return; 1133 } 1134 1135 info = page_dir[idx]; 1136 1137 if (info < MALLOC_MAGIC) 1138 free_pages(ptr, idx, info); 1139 else 1140 free_bytes(ptr, idx, info); 1141 return; 1142 } 1143 1144 static int malloc_active; /* Recusion flag for public interface. */ 1145 static unsigned malloc_started; /* Set when initialization has been done */ 1146 1147 static void * 1148 pubrealloc(void *ptr, size_t size, const char *func) 1149 { 1150 void *r; 1151 int err = 0; 1152 1153 /* 1154 * If a thread is inside our code with a functional lock held, and then 1155 * catches a signal which calls us again, we would get a deadlock if the 1156 * lock is not of a recursive type. 1157 */ 1158 _MALLOC_LOCK(); 1159 malloc_func = func; 1160 if (malloc_active > 0) { 1161 if (malloc_active == 1) { 1162 wrtwarning("recursive call\n"); 1163 malloc_active = 2; 1164 } 1165 _MALLOC_UNLOCK(); 1166 errno = EINVAL; 1167 return (NULL); 1168 } 1169 malloc_active = 1; 1170 1171 if (!malloc_started) { 1172 if (ptr != NULL) { 1173 wrtwarning("malloc() has never been called\n"); 1174 malloc_active = 0; 1175 _MALLOC_UNLOCK(); 1176 errno = EINVAL; 1177 return (NULL); 1178 } 1179 malloc_init(); 1180 malloc_started = 1; 1181 } 1182 1183 if (ptr == ZEROSIZEPTR) 1184 ptr = NULL; 1185 if (malloc_sysv && !size) { 1186 if (ptr != NULL) 1187 ifree(ptr); 1188 r = NULL; 1189 } else if (!size) { 1190 if (ptr != NULL) 1191 ifree(ptr); 1192 r = ZEROSIZEPTR; 1193 } else if (ptr == NULL) { 1194 r = imalloc(size); 1195 err = (r == NULL); 1196 } else { 1197 r = irealloc(ptr, size); 1198 err = (r == NULL); 1199 } 1200 UTRACE(ptr, size, r); 1201 malloc_active = 0; 1202 _MALLOC_UNLOCK(); 1203 if (malloc_xmalloc && err) 1204 wrterror("out of memory\n"); 1205 if (err) 1206 errno = ENOMEM; 1207 return (r); 1208 } 1209 1210 /* 1211 * These are the public exported interface routines. 1212 */ 1213 1214 void * 1215 malloc(size_t size) 1216 { 1217 1218 return pubrealloc(NULL, size, " in malloc():"); 1219 } 1220 1221 int 1222 posix_memalign(void **memptr, size_t alignment, size_t size) 1223 { 1224 int err; 1225 void *result; 1226 1227 if (!malloc_started) { 1228 malloc_init(); 1229 malloc_started = 1; 1230 } 1231 /* Make sure that alignment is a large enough power of 2. */ 1232 if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *) || 1233 alignment > malloc_pagesize) 1234 return EINVAL; 1235 1236 /* 1237 * (size | alignment) is enough to assure the requested alignment, since 1238 * the allocator always allocates power-of-two blocks. 1239 */ 1240 err = errno; /* Protect errno against changes in pubrealloc(). */ 1241 result = pubrealloc(NULL, (size | alignment), " in posix_memalign()"); 1242 errno = err; 1243 1244 if (result == NULL) 1245 return ENOMEM; 1246 1247 *memptr = result; 1248 return 0; 1249 } 1250 1251 void * 1252 calloc(size_t num, size_t size) 1253 { 1254 void *ret; 1255 1256 if (size != 0 && (num * size) / size != num) { 1257 /* size_t overflow. */ 1258 errno = ENOMEM; 1259 return (NULL); 1260 } 1261 1262 ret = pubrealloc(NULL, num * size, " in calloc():"); 1263 1264 if (ret != NULL) 1265 memset(ret, 0, num * size); 1266 1267 return ret; 1268 } 1269 1270 void 1271 free(void *ptr) 1272 { 1273 1274 pubrealloc(ptr, 0, " in free():"); 1275 } 1276 1277 void * 1278 realloc(void *ptr, size_t size) 1279 { 1280 1281 return pubrealloc(ptr, size, " in realloc():"); 1282 } 1283 1284 /* 1285 * Begin library-private functions, used by threading libraries for protection 1286 * of malloc during fork(). These functions are only called if the program is 1287 * running in threaded mode, so there is no need to check whether the program 1288 * is threaded here. 1289 */ 1290 1291 void 1292 _malloc_prefork(void) 1293 { 1294 1295 _MALLOC_LOCK(); 1296 } 1297 1298 void 1299 _malloc_postfork(void) 1300 { 1301 1302 _MALLOC_UNLOCK(); 1303 } 1304