summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm <>2009-01-03 12:58:28 +0000
committerdjm <>2009-01-03 12:58:28 +0000
commitacc5957d1b6d6872ce50e4100edebccea0476481 (patch)
treedcddf4a13e571e69a5ef0b1249ddf4a5bd1b6833
parent6ed7af51f222ca8ff51d9386632cc02cabeb0a58 (diff)
downloadopenbsd-acc5957d1b6d6872ce50e4100edebccea0476481.tar.gz
openbsd-acc5957d1b6d6872ce50e4100edebccea0476481.tar.bz2
openbsd-acc5957d1b6d6872ce50e4100edebccea0476481.zip
reintroduce extra malloc protections, but avoiding the use of
PAGE_(SIZE|SHIFT|MASK) defines that evaluate to variables on the sparc architecture; ok otto@ tested on my reanimated ss20
-rw-r--r--src/lib/libc/stdlib/malloc.c393
1 files changed, 229 insertions, 164 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index d46207360c..2ce545c5fa 100644
--- a/src/lib/libc/stdlib/malloc.c
+++ b/src/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: malloc.c,v 1.114 2008/12/31 05:21:46 deraadt Exp $ */ 1/* $OpenBSD: malloc.c,v 1.115 2009/01/03 12:58:28 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> 3 * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
4 * 4 *
@@ -125,7 +125,8 @@ struct dir_info {
125#endif /* MALLOC_STATS */ 125#endif /* MALLOC_STATS */
126 u_int32_t canary2; 126 u_int32_t canary2;
127}; 127};
128 128#define DIR_INFO_RSZ ((sizeof(struct dir_info) + MALLOC_PAGEMASK) & \
129 ~MALLOC_PAGEMASK)
129 130
130/* 131/*
131 * This structure describes a page worth of chunks. 132 * This structure describes a page worth of chunks.
@@ -145,29 +146,40 @@ struct chunk_info {
145 u_long bits[(MALLOC_PAGESIZE / MALLOC_MINSIZE) / MALLOC_BITS]; 146 u_long bits[(MALLOC_PAGESIZE / MALLOC_MINSIZE) / MALLOC_BITS];
146}; 147};
147 148
148static struct dir_info g_pool; 149struct malloc_readonly {
149static char *malloc_func; /* current function */ 150 struct dir_info *g_pool; /* Main bookkeeping information */
151 int malloc_abort; /* abort() on error */
152 int malloc_freeprot; /* mprotect free pages PROT_NONE? */
153 int malloc_hint; /* call madvice on free pages? */
154 int malloc_junk; /* junk fill? */
155 int malloc_move; /* move allocations to end of page? */
156 int malloc_realloc; /* always realloc? */
157 int malloc_xmalloc; /* xmalloc behaviour? */
158 int malloc_zero; /* zero fill? */
159 size_t malloc_guard; /* use guard pages after allocations? */
160 u_int malloc_cache; /* free pages we cache */
161#ifdef MALLOC_STATS
162 int malloc_stats; /* dump statistics at end */
163#endif
164 u_int32_t malloc_canary; /* Matched against ones in g_pool */
165};
166
167/* This object is mapped PROT_READ after initialisation to prevent tampering */
168static union {
169 struct malloc_readonly mopts;
170 u_char _pad[MALLOC_PAGESIZE];
171} malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE)));
172#define mopts malloc_readonly.mopts
173#define g_pool mopts.g_pool
174
150char *malloc_options; /* compile-time options */ 175char *malloc_options; /* compile-time options */
151 176
152static int malloc_abort = 1; /* abort() on error */ 177static char *malloc_func; /* current function */
153static int malloc_active; /* status of malloc */ 178static int malloc_active; /* status of malloc */
154static int malloc_freeprot; /* mprotect free pages PROT_NONE? */ 179
155static int malloc_hint; /* call madvice on free pages? */
156static int malloc_junk; /* junk fill? */
157static int malloc_move = 1; /* move allocations to end of page? */
158static int malloc_realloc; /* always realloc? */
159static int malloc_xmalloc; /* xmalloc behaviour? */
160static int malloc_zero; /* zero fill? */
161static size_t malloc_guard; /* use guard pages after allocations? */
162
163static u_int malloc_cache = 64; /* free pages we cache */
164static size_t malloc_guarded; /* bytes used for guards */ 180static size_t malloc_guarded; /* bytes used for guards */
165static size_t malloc_used; /* bytes allocated */ 181static size_t malloc_used; /* bytes allocated */
166 182
167#ifdef MALLOC_STATS
168static int malloc_stats; /* dump statistics at end */
169#endif
170
171static size_t rbytesused; /* random bytes used */ 183static size_t rbytesused; /* random bytes used */
172static u_char rbytes[512]; /* random bytes */ 184static u_char rbytes[512]; /* random bytes */
173static u_char getrbyte(void); 185static u_char getrbyte(void);
@@ -247,7 +259,7 @@ dump_free_page_info(int fd, struct dir_info *d)
247 snprintf(buf, sizeof(buf), "Free pages cached: %zu\n", 259 snprintf(buf, sizeof(buf), "Free pages cached: %zu\n",
248 d->free_regions_size); 260 d->free_regions_size);
249 write(fd, buf, strlen(buf)); 261 write(fd, buf, strlen(buf));
250 for (i = 0; i < malloc_cache; i++) { 262 for (i = 0; i < mopts.malloc_cache; i++) {
251 if (d->free_regions[i].p != NULL) { 263 if (d->free_regions[i].p != NULL) {
252 snprintf(buf, sizeof(buf), "%2d) ", i); 264 snprintf(buf, sizeof(buf), "%2d) ", i);
253 write(fd, buf, strlen(buf)); 265 write(fd, buf, strlen(buf));
@@ -266,6 +278,8 @@ malloc_dump1(int fd, struct dir_info *d)
266 278
267 snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d); 279 snprintf(buf, sizeof(buf), "Malloc dir of %s at %p\n", __progname, d);
268 write(fd, buf, strlen(buf)); 280 write(fd, buf, strlen(buf));
281 if (d == NULL)
282 return;
269 snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total); 283 snprintf(buf, sizeof(buf), "Regions slots %zu\n", d->regions_total);
270 write(fd, buf, strlen(buf)); 284 write(fd, buf, strlen(buf));
271 snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds, 285 snprintf(buf, sizeof(buf), "Finds %zu/%zu %f\n", d->finds,
@@ -313,7 +327,7 @@ malloc_dump1(int fd, struct dir_info *d)
313void 327void
314malloc_dump(int fd) 328malloc_dump(int fd)
315{ 329{
316 malloc_dump1(fd, &g_pool); 330 malloc_dump1(fd, g_pool);
317} 331}
318 332
319static void 333static void
@@ -353,11 +367,11 @@ wrterror(char *p)
353 writev(STDERR_FILENO, iov, 5); 367 writev(STDERR_FILENO, iov, 5);
354 368
355#ifdef MALLOC_STATS 369#ifdef MALLOC_STATS
356 if (malloc_stats) 370 if (mopts.malloc_stats)
357 malloc_dump(STDERR_FILENO); 371 malloc_dump(STDERR_FILENO);
358#endif /* MALLOC_STATS */ 372#endif /* MALLOC_STATS */
359 //malloc_active--; 373 //malloc_active--;
360 if (malloc_abort) 374 if (mopts.malloc_abort)
361 abort(); 375 abort();
362} 376}
363 377
@@ -381,19 +395,19 @@ unmap(struct dir_info *d, void *p, size_t sz)
381 return; 395 return;
382 } 396 }
383 397
384 if (psz > malloc_cache) { 398 if (psz > mopts.malloc_cache) {
385 if (munmap(p, sz)) 399 if (munmap(p, sz))
386 wrterror("munmap"); 400 wrterror("munmap");
387 malloc_used -= sz; 401 malloc_used -= sz;
388 return; 402 return;
389 } 403 }
390 tounmap = 0; 404 tounmap = 0;
391 rsz = malloc_cache - d->free_regions_size; 405 rsz = mopts.malloc_cache - d->free_regions_size;
392 if (psz > rsz) 406 if (psz > rsz)
393 tounmap = psz - rsz; 407 tounmap = psz - rsz;
394 offset = getrbyte(); 408 offset = getrbyte();
395 for (i = 0; tounmap > 0 && i < malloc_cache; i++) { 409 for (i = 0; tounmap > 0 && i < mopts.malloc_cache; i++) {
396 r = &d->free_regions[(i + offset) & (malloc_cache - 1)]; 410 r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)];
397 if (r->p != NULL) { 411 if (r->p != NULL) {
398 rsz = r->size << MALLOC_PAGESHIFT; 412 rsz = r->size << MALLOC_PAGESHIFT;
399 if (munmap(r->p, rsz)) 413 if (munmap(r->p, rsz))
@@ -410,12 +424,12 @@ unmap(struct dir_info *d, void *p, size_t sz)
410 } 424 }
411 if (tounmap > 0) 425 if (tounmap > 0)
412 wrterror("malloc cache underflow"); 426 wrterror("malloc cache underflow");
413 for (i = 0; i < malloc_cache; i++) { 427 for (i = 0; i < mopts.malloc_cache; i++) {
414 r = &d->free_regions[i]; 428 r = &d->free_regions[i];
415 if (r->p == NULL) { 429 if (r->p == NULL) {
416 if (malloc_hint) 430 if (mopts.malloc_hint)
417 madvise(p, sz, MADV_FREE); 431 madvise(p, sz, MADV_FREE);
418 if (malloc_freeprot) 432 if (mopts.malloc_freeprot)
419 mprotect(p, sz, PROT_NONE); 433 mprotect(p, sz, PROT_NONE);
420 r->p = p; 434 r->p = p;
421 r->size = psz; 435 r->size = psz;
@@ -423,9 +437,9 @@ unmap(struct dir_info *d, void *p, size_t sz)
423 break; 437 break;
424 } 438 }
425 } 439 }
426 if (i == malloc_cache) 440 if (i == mopts.malloc_cache)
427 wrterror("malloc free slot lost"); 441 wrterror("malloc free slot lost");
428 if (d->free_regions_size > malloc_cache) 442 if (d->free_regions_size > mopts.malloc_cache)
429 wrterror("malloc cache overflow"); 443 wrterror("malloc cache overflow");
430} 444}
431 445
@@ -436,7 +450,7 @@ zapcacheregion(struct dir_info *d, void *p)
436 struct region_info *r; 450 struct region_info *r;
437 size_t rsz; 451 size_t rsz;
438 452
439 for (i = 0; i < malloc_cache; i++) { 453 for (i = 0; i < mopts.malloc_cache; i++) {
440 r = &d->free_regions[i]; 454 r = &d->free_regions[i];
441 if (r->p == p) { 455 if (r->p == p) {
442 rsz = r->size << MALLOC_PAGESHIFT; 456 rsz = r->size << MALLOC_PAGESHIFT;
@@ -458,6 +472,9 @@ map(struct dir_info *d, size_t sz, int zero_fill)
458 u_int i, offset; 472 u_int i, offset;
459 void *p; 473 void *p;
460 474
475 if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
476 d->canary1 != ~d->canary2)
477 wrterror("internal struct corrupt");
461 if (sz != PAGEROUND(sz)) { 478 if (sz != PAGEROUND(sz)) {
462 wrterror("map round"); 479 wrterror("map round");
463 return NULL; 480 return NULL;
@@ -470,21 +487,22 @@ map(struct dir_info *d, size_t sz, int zero_fill)
470 return p; 487 return p;
471 } 488 }
472 offset = getrbyte(); 489 offset = getrbyte();
473 for (i = 0; i < malloc_cache; i++) { 490 for (i = 0; i < mopts.malloc_cache; i++) {
474 r = &d->free_regions[(i + offset) & (malloc_cache - 1)]; 491 r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)];
475 if (r->p != NULL) { 492 if (r->p != NULL) {
476 if (r->size == psz) { 493 if (r->size == psz) {
477 p = r->p; 494 p = r->p;
478 if (malloc_freeprot) 495 if (mopts.malloc_freeprot)
479 mprotect(p, sz, PROT_READ | PROT_WRITE); 496 mprotect(p, sz, PROT_READ | PROT_WRITE);
480 if (malloc_hint) 497 if (mopts.malloc_hint)
481 madvise(p, sz, MADV_NORMAL); 498 madvise(p, sz, MADV_NORMAL);
482 r->p = NULL; 499 r->p = NULL;
483 r->size = 0; 500 r->size = 0;
484 d->free_regions_size -= psz; 501 d->free_regions_size -= psz;
485 if (zero_fill) 502 if (zero_fill)
486 memset(p, 0, sz); 503 memset(p, 0, sz);
487 else if (malloc_junk && malloc_freeprot) 504 else if (mopts.malloc_junk &&
505 mopts.malloc_freeprot)
488 memset(p, SOME_FREEJUNK, sz); 506 memset(p, SOME_FREEJUNK, sz);
489 return p; 507 return p;
490 } else if (r->size > psz) 508 } else if (r->size > psz)
@@ -494,9 +512,9 @@ map(struct dir_info *d, size_t sz, int zero_fill)
494 if (big != NULL) { 512 if (big != NULL) {
495 r = big; 513 r = big;
496 p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT); 514 p = (char *)r->p + ((r->size - psz) << MALLOC_PAGESHIFT);
497 if (malloc_freeprot) 515 if (mopts.malloc_freeprot)
498 mprotect(p, sz, PROT_READ | PROT_WRITE); 516 mprotect(p, sz, PROT_READ | PROT_WRITE);
499 if (malloc_hint) 517 if (mopts.malloc_hint)
500 madvise(p, sz, MADV_NORMAL); 518 madvise(p, sz, MADV_NORMAL);
501 r->size -= psz; 519 r->size -= psz;
502 d->free_regions_size -= psz; 520 d->free_regions_size -= psz;
@@ -507,7 +525,7 @@ map(struct dir_info *d, size_t sz, int zero_fill)
507 p = MMAP(sz); 525 p = MMAP(sz);
508 if (p != MAP_FAILED) 526 if (p != MAP_FAILED)
509 malloc_used += sz; 527 malloc_used += sz;
510 if (d->free_regions_size > malloc_cache) 528 if (d->free_regions_size > mopts.malloc_cache)
511 wrterror("malloc cache"); 529 wrterror("malloc cache");
512 /* zero fill not needed */ 530 /* zero fill not needed */
513 return p; 531 return p;
@@ -532,14 +550,22 @@ getrbyte(void)
532 * Initialize a dir_info, which should have been cleared by caller 550 * Initialize a dir_info, which should have been cleared by caller
533 */ 551 */
534static int 552static int
535omalloc_init(struct dir_info *d) 553omalloc_init(struct dir_info **dp)
536{ 554{
537 char *p, b[64]; 555 char *p, b[64];
538 int i, j; 556 int i, j;
539 size_t regioninfo_size; 557 size_t d_avail, regioninfo_size;
558 struct dir_info *d;
540 559
541 rbytes_init(); 560 rbytes_init();
542 561
562 /*
563 * Default options
564 */
565 mopts.malloc_abort = 1;
566 mopts.malloc_move = 1;
567 mopts.malloc_cache = 64;
568
543 for (i = 0; i < 3; i++) { 569 for (i = 0; i < 3; i++) {
544 switch (i) { 570 switch (i) {
545 case 0: 571 case 0:
@@ -565,77 +591,77 @@ omalloc_init(struct dir_info *d)
565 for (; p != NULL && *p != '\0'; p++) { 591 for (; p != NULL && *p != '\0'; p++) {
566 switch (*p) { 592 switch (*p) {
567 case '>': 593 case '>':
568 malloc_cache <<= 1; 594 mopts.malloc_cache <<= 1;
569 if (malloc_cache > MALLOC_MAXCACHE) 595 if (mopts.malloc_cache > MALLOC_MAXCACHE)
570 malloc_cache = MALLOC_MAXCACHE; 596 mopts.malloc_cache = MALLOC_MAXCACHE;
571 break; 597 break;
572 case '<': 598 case '<':
573 malloc_cache >>= 1; 599 mopts.malloc_cache >>= 1;
574 break; 600 break;
575 case 'a': 601 case 'a':
576 malloc_abort = 0; 602 mopts.malloc_abort = 0;
577 break; 603 break;
578 case 'A': 604 case 'A':
579 malloc_abort = 1; 605 mopts.malloc_abort = 1;
580 break; 606 break;
581#ifdef MALLOC_STATS 607#ifdef MALLOC_STATS
582 case 'd': 608 case 'd':
583 malloc_stats = 0; 609 mopts.malloc_stats = 0;
584 break; 610 break;
585 case 'D': 611 case 'D':
586 malloc_stats = 1; 612 mopts.malloc_stats = 1;
587 break; 613 break;
588#endif /* MALLOC_STATS */ 614#endif /* MALLOC_STATS */
589 case 'f': 615 case 'f':
590 malloc_freeprot = 0; 616 mopts.malloc_freeprot = 0;
591 break; 617 break;
592 case 'F': 618 case 'F':
593 malloc_freeprot = 1; 619 mopts.malloc_freeprot = 1;
594 break; 620 break;
595 case 'g': 621 case 'g':
596 malloc_guard = 0; 622 mopts.malloc_guard = 0;
597 break; 623 break;
598 case 'G': 624 case 'G':
599 malloc_guard = MALLOC_PAGESIZE; 625 mopts.malloc_guard = MALLOC_PAGESIZE;
600 break; 626 break;
601 case 'h': 627 case 'h':
602 malloc_hint = 0; 628 mopts.malloc_hint = 0;
603 break; 629 break;
604 case 'H': 630 case 'H':
605 malloc_hint = 1; 631 mopts.malloc_hint = 1;
606 break; 632 break;
607 case 'j': 633 case 'j':
608 malloc_junk = 0; 634 mopts.malloc_junk = 0;
609 break; 635 break;
610 case 'J': 636 case 'J':
611 malloc_junk = 1; 637 mopts.malloc_junk = 1;
612 break; 638 break;
613 case 'n': 639 case 'n':
614 case 'N': 640 case 'N':
615 break; 641 break;
616 case 'p': 642 case 'p':
617 malloc_move = 0; 643 mopts.malloc_move = 0;
618 break; 644 break;
619 case 'P': 645 case 'P':
620 malloc_move = 1; 646 mopts.malloc_move = 1;
621 break; 647 break;
622 case 'r': 648 case 'r':
623 malloc_realloc = 0; 649 mopts.malloc_realloc = 0;
624 break; 650 break;
625 case 'R': 651 case 'R':
626 malloc_realloc = 1; 652 mopts.malloc_realloc = 1;
627 break; 653 break;
628 case 'x': 654 case 'x':
629 malloc_xmalloc = 0; 655 mopts.malloc_xmalloc = 0;
630 break; 656 break;
631 case 'X': 657 case 'X':
632 malloc_xmalloc = 1; 658 mopts.malloc_xmalloc = 1;
633 break; 659 break;
634 case 'z': 660 case 'z':
635 malloc_zero = 0; 661 mopts.malloc_zero = 0;
636 break; 662 break;
637 case 'Z': 663 case 'Z':
638 malloc_zero = 1; 664 mopts.malloc_zero = 1;
639 break; 665 break;
640 default: { 666 default: {
641 static const char q[] = "malloc() warning: " 667 static const char q[] = "malloc() warning: "
@@ -651,17 +677,34 @@ omalloc_init(struct dir_info *d)
651 * We want junk in the entire allocation, and zero only in the part 677 * We want junk in the entire allocation, and zero only in the part
652 * the user asked for. 678 * the user asked for.
653 */ 679 */
654 if (malloc_zero) 680 if (mopts.malloc_zero)
655 malloc_junk = 1; 681 mopts.malloc_junk = 1;
656 682
657#ifdef MALLOC_STATS 683#ifdef MALLOC_STATS
658 if (malloc_stats && (atexit(malloc_exit) == -1)) { 684 if (mopts.malloc_stats && (atexit(malloc_exit) == -1)) {
659 static const char q[] = "malloc() warning: atexit(2) failed." 685 static const char q[] = "malloc() warning: atexit(2) failed."
660 " Will not be able to dump stats on exit\n"; 686 " Will not be able to dump stats on exit\n";
661 write(STDERR_FILENO, q, sizeof(q) - 1); 687 write(STDERR_FILENO, q, sizeof(q) - 1);
662 } 688 }
663#endif /* MALLOC_STATS */ 689#endif /* MALLOC_STATS */
664 690
691 while ((mopts.malloc_canary = arc4random()) == 0)
692 ;
693
694 /*
695 * Allocate dir_info with a guard page on either side. Also
696 * randomise offset inside the page at which the dir_info
697 * lies (subject to alignment by 1 << MALLOC_MINSHIFT)
698 */
699 if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == NULL)
700 return -1;
701 mprotect(p, MALLOC_PAGESIZE, PROT_NONE);
702 mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ,
703 MALLOC_PAGESIZE, PROT_NONE);
704 d_avail = (DIR_INFO_RSZ - sizeof(*d)) >> MALLOC_MINSHIFT;
705 d = (struct dir_info *)(p + MALLOC_PAGESIZE +
706 (arc4random_uniform(d_avail) << MALLOC_MINSHIFT));
707
665 d->regions_bits = 9; 708 d->regions_bits = 9;
666 d->regions_free = d->regions_total = 1 << d->regions_bits; 709 d->regions_free = d->regions_total = 1 << d->regions_bits;
667 regioninfo_size = d->regions_total * sizeof(struct region_info); 710 regioninfo_size = d->regions_total * sizeof(struct region_info);
@@ -673,8 +716,18 @@ omalloc_init(struct dir_info *d)
673 } 716 }
674 malloc_used += regioninfo_size; 717 malloc_used += regioninfo_size;
675 memset(d->r, 0, regioninfo_size); 718 memset(d->r, 0, regioninfo_size);
676 d->canary1 = arc4random(); 719 d->canary1 = mopts.malloc_canary ^ (u_int32_t)d;
677 d->canary2 = ~d->canary1; 720 d->canary2 = ~d->canary1;
721
722 *dp = d;
723
724 /*
725 * Options have been set and will never be reset.
726 * Prevent further tampering with them.
727 */
728 if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0)
729 mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ);
730
678 return 0; 731 return 0;
679} 732}
680 733
@@ -792,7 +845,8 @@ find(struct dir_info *d, void *p)
792 size_t mask = d->regions_total - 1; 845 size_t mask = d->regions_total - 1;
793 void *q, *r; 846 void *q, *r;
794 847
795 if (d->canary1 != ~d->canary2) 848 if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
849 d->canary1 != ~d->canary2)
796 wrterror("internal struct corrupt"); 850 wrterror("internal struct corrupt");
797 p = MASK_POINTER(p); 851 p = MASK_POINTER(p);
798 index = hash(p) & mask; 852 index = hash(p) & mask;
@@ -818,7 +872,7 @@ delete(struct dir_info *d, struct region_info *ri)
818 if (d->regions_total & (d->regions_total - 1)) 872 if (d->regions_total & (d->regions_total - 1))
819 wrterror("regions_total not 2^x"); 873 wrterror("regions_total not 2^x");
820 d->regions_free++; 874 d->regions_free++;
821 STATS_INC(g_pool.deletes); 875 STATS_INC(g_pool->deletes);
822 876
823 i = ri - d->r; 877 i = ri - d->r;
824 for (;;) { 878 for (;;) {
@@ -834,7 +888,7 @@ delete(struct dir_info *d, struct region_info *ri)
834 (j < i && i <= r)) 888 (j < i && i <= r))
835 continue; 889 continue;
836 d->r[j] = d->r[i]; 890 d->r[j] = d->r[i];
837 STATS_INC(g_pool.delete_moves); 891 STATS_INC(g_pool->delete_moves);
838 break; 892 break;
839 } 893 }
840 894
@@ -919,6 +973,9 @@ malloc_bytes(struct dir_info *d, size_t size)
919 u_long u, *lp; 973 u_long u, *lp;
920 struct chunk_info *bp; 974 struct chunk_info *bp;
921 975
976 if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)d) ||
977 d->canary1 != ~d->canary2)
978 wrterror("internal struct corrupt");
922 /* Don't bother with anything less than this */ 979 /* Don't bother with anything less than this */
923 /* unless we have a malloc(0) requests */ 980 /* unless we have a malloc(0) requests */
924 if (size != 0 && size < MALLOC_MINSIZE) 981 if (size != 0 && size < MALLOC_MINSIZE)
@@ -983,7 +1040,7 @@ malloc_bytes(struct dir_info *d, size_t size)
983 k += (lp - bp->bits) * MALLOC_BITS; 1040 k += (lp - bp->bits) * MALLOC_BITS;
984 k <<= bp->shift; 1041 k <<= bp->shift;
985 1042
986 if (malloc_junk && bp->size > 0) 1043 if (mopts.malloc_junk && bp->size > 0)
987 memset((char *)bp->page + k, SOME_JUNK, bp->size); 1044 memset((char *)bp->page + k, SOME_JUNK, bp->size);
988 return ((char *)bp->page + k); 1045 return ((char *)bp->page + k);
989} 1046}
@@ -1047,7 +1104,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1047 } 1104 }
1048 *mp = info->next; 1105 *mp = info->next;
1049 1106
1050 if (info->size == 0 && !malloc_freeprot) 1107 if (info->size == 0 && !mopts.malloc_freeprot)
1051 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); 1108 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
1052 unmap(d, info->page, MALLOC_PAGESIZE); 1109 unmap(d, info->page, MALLOC_PAGESIZE);
1053 1110
@@ -1064,54 +1121,55 @@ omalloc(size_t sz, int zero_fill)
1064 size_t psz; 1121 size_t psz;
1065 1122
1066 if (sz > MALLOC_MAXCHUNK) { 1123 if (sz > MALLOC_MAXCHUNK) {
1067 if (sz >= SIZE_MAX - malloc_guard - MALLOC_PAGESIZE) { 1124 if (sz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
1068 errno = ENOMEM; 1125 errno = ENOMEM;
1069 return NULL; 1126 return NULL;
1070 } 1127 }
1071 sz += malloc_guard; 1128 sz += mopts.malloc_guard;
1072 psz = PAGEROUND(sz); 1129 psz = PAGEROUND(sz);
1073 p = map(&g_pool, psz, zero_fill); 1130 p = map(g_pool, psz, zero_fill);
1074 if (p == MAP_FAILED) { 1131 if (p == MAP_FAILED) {
1075 errno = ENOMEM; 1132 errno = ENOMEM;
1076 return NULL; 1133 return NULL;
1077 } 1134 }
1078 if (insert(&g_pool, p, sz)) { 1135 if (insert(g_pool, p, sz)) {
1079 unmap(&g_pool, p, psz); 1136 unmap(g_pool, p, psz);
1080 errno = ENOMEM; 1137 errno = ENOMEM;
1081 return NULL; 1138 return NULL;
1082 } 1139 }
1083 if (malloc_guard) { 1140 if (mopts.malloc_guard) {
1084 if (mprotect((char *)p + psz - malloc_guard, 1141 if (mprotect((char *)p + psz - mopts.malloc_guard,
1085 malloc_guard, PROT_NONE)) 1142 mopts.malloc_guard, PROT_NONE))
1086 wrterror("mprotect"); 1143 wrterror("mprotect");
1087 malloc_guarded += malloc_guard; 1144 malloc_guarded += mopts.malloc_guard;
1088 } 1145 }
1089 1146
1090 if (malloc_move && 1147 if (mopts.malloc_move &&
1091 sz - malloc_guard < MALLOC_PAGESIZE - MALLOC_LEEWAY) { 1148 sz - mopts.malloc_guard < MALLOC_PAGESIZE -
1149 MALLOC_LEEWAY) {
1092 /* fill whole allocation */ 1150 /* fill whole allocation */
1093 if (malloc_junk) 1151 if (mopts.malloc_junk)
1094 memset(p, SOME_JUNK, psz - malloc_guard); 1152 memset(p, SOME_JUNK, psz - mopts.malloc_guard);
1095 /* shift towards the end */ 1153 /* shift towards the end */
1096 p = ((char *)p) + ((MALLOC_PAGESIZE - MALLOC_LEEWAY - 1154 p = ((char *)p) + ((MALLOC_PAGESIZE - MALLOC_LEEWAY -
1097 (sz - malloc_guard)) & ~(MALLOC_MINSIZE-1)); 1155 (sz - mopts.malloc_guard)) & ~(MALLOC_MINSIZE-1));
1098 /* fill zeros if needed and overwritten above */ 1156 /* fill zeros if needed and overwritten above */
1099 if (zero_fill && malloc_junk) 1157 if (zero_fill && mopts.malloc_junk)
1100 memset(p, 0, sz - malloc_guard); 1158 memset(p, 0, sz - mopts.malloc_guard);
1101 } else { 1159 } else {
1102 if (malloc_junk) { 1160 if (mopts.malloc_junk) {
1103 if (zero_fill) 1161 if (zero_fill)
1104 memset(p + sz - malloc_guard, 1162 memset(p + sz - mopts.malloc_guard,
1105 SOME_JUNK, psz - sz); 1163 SOME_JUNK, psz - sz);
1106 else 1164 else
1107 memset(p, 1165 memset(p, SOME_JUNK,
1108 SOME_JUNK, psz - malloc_guard); 1166 psz - mopts.malloc_guard);
1109 } 1167 }
1110 } 1168 }
1111 1169
1112 } else { 1170 } else {
1113 /* takes care of SOME_JUNK */ 1171 /* takes care of SOME_JUNK */
1114 p = malloc_bytes(&g_pool, sz); 1172 p = malloc_bytes(g_pool, sz);
1115 if (zero_fill && p != NULL && sz > 0) 1173 if (zero_fill && p != NULL && sz > 0)
1116 memset(p, 0, sz); 1174 memset(p, 0, sz);
1117 } 1175 }
@@ -1138,6 +1196,19 @@ malloc_recurse(void)
1138 errno = EDEADLK; 1196 errno = EDEADLK;
1139} 1197}
1140 1198
1199static int
1200malloc_init(void)
1201{
1202 if (omalloc_init(&g_pool)) {
1203 _MALLOC_UNLOCK();
1204 if (mopts.malloc_xmalloc)
1205 wrterror("out of memory");
1206 errno = ENOMEM;
1207 return -1;
1208 }
1209 return 0;
1210}
1211
1141void * 1212void *
1142malloc(size_t size) 1213malloc(size_t size)
1143{ 1214{
@@ -1146,23 +1217,18 @@ malloc(size_t size)
1146 1217
1147 _MALLOC_LOCK(); 1218 _MALLOC_LOCK();
1148 malloc_func = " in malloc():"; 1219 malloc_func = " in malloc():";
1149 if (!g_pool.regions_total) { 1220 if (g_pool == NULL) {
1150 if (omalloc_init(&g_pool)) { 1221 if (malloc_init() != 0)
1151 _MALLOC_UNLOCK();
1152 if (malloc_xmalloc)
1153 wrterror("out of memory");
1154 errno = ENOMEM;
1155 return NULL; 1222 return NULL;
1156 }
1157 } 1223 }
1158 if (malloc_active++) { 1224 if (malloc_active++) {
1159 malloc_recurse(); 1225 malloc_recurse();
1160 return NULL; 1226 return NULL;
1161 } 1227 }
1162 r = omalloc(size, malloc_zero); 1228 r = omalloc(size, mopts.malloc_zero);
1163 malloc_active--; 1229 malloc_active--;
1164 _MALLOC_UNLOCK(); 1230 _MALLOC_UNLOCK();
1165 if (r == NULL && malloc_xmalloc) { 1231 if (r == NULL && mopts.malloc_xmalloc) {
1166 wrterror("out of memory"); 1232 wrterror("out of memory");
1167 errno = ENOMEM; 1233 errno = ENOMEM;
1168 } 1234 }
@@ -1177,14 +1243,15 @@ ofree(void *p)
1177 struct region_info *r; 1243 struct region_info *r;
1178 size_t sz; 1244 size_t sz;
1179 1245
1180 r = find(&g_pool, p); 1246 r = find(g_pool, p);
1181 if (r == NULL) { 1247 if (r == NULL) {
1182 wrterror("bogus pointer (double free?)"); 1248 wrterror("bogus pointer (double free?)");
1183 return; 1249 return;
1184 } 1250 }
1185 REALSIZE(sz, r); 1251 REALSIZE(sz, r);
1186 if (sz > MALLOC_MAXCHUNK) { 1252 if (sz > MALLOC_MAXCHUNK) {
1187 if (sz - malloc_guard >= MALLOC_PAGESIZE - MALLOC_LEEWAY) { 1253 if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE -
1254 MALLOC_LEEWAY) {
1188 if (r->p != p) { 1255 if (r->p != p) {
1189 wrterror("bogus pointer"); 1256 wrterror("bogus pointer");
1190 return; 1257 return;
@@ -1193,46 +1260,47 @@ ofree(void *p)
1193#if notyetbecause_of_realloc 1260#if notyetbecause_of_realloc
1194 /* shifted towards the end */ 1261 /* shifted towards the end */
1195 if (p != ((char *)r->p) + ((MALLOC_PAGESIZE - 1262 if (p != ((char *)r->p) + ((MALLOC_PAGESIZE -
1196 MALLOC_MINSIZE - sz - malloc_guard) & 1263 MALLOC_MINSIZE - sz - mopts.malloc_guard) &
1197 ~(MALLOC_MINSIZE-1))) { 1264 ~(MALLOC_MINSIZE-1))) {
1198 } 1265 }
1199#endif 1266#endif
1200 p = r->p; 1267 p = r->p;
1201 } 1268 }
1202 if (malloc_guard) { 1269 if (mopts.malloc_guard) {
1203 if (sz < malloc_guard) 1270 if (sz < mopts.malloc_guard)
1204 wrterror("guard size"); 1271 wrterror("guard size");
1205 if (!malloc_freeprot) { 1272 if (!mopts.malloc_freeprot) {
1206 if (mprotect((char *)p + PAGEROUND(sz) - 1273 if (mprotect((char *)p + PAGEROUND(sz) -
1207 malloc_guard, malloc_guard, 1274 mopts.malloc_guard, mopts.malloc_guard,
1208 PROT_READ | PROT_WRITE)) 1275 PROT_READ | PROT_WRITE))
1209 wrterror("mprotect"); 1276 wrterror("mprotect");
1210 } 1277 }
1211 malloc_guarded -= malloc_guard; 1278 malloc_guarded -= mopts.malloc_guard;
1212 } 1279 }
1213 if (malloc_junk && !malloc_freeprot) 1280 if (mopts.malloc_junk && !mopts.malloc_freeprot)
1214 memset(p, SOME_FREEJUNK, PAGEROUND(sz) - malloc_guard); 1281 memset(p, SOME_FREEJUNK,
1215 unmap(&g_pool, p, PAGEROUND(sz)); 1282 PAGEROUND(sz) - mopts.malloc_guard);
1216 delete(&g_pool, r); 1283 unmap(g_pool, p, PAGEROUND(sz));
1284 delete(g_pool, r);
1217 } else { 1285 } else {
1218 void *tmp; 1286 void *tmp;
1219 int i; 1287 int i;
1220 1288
1221 if (malloc_junk && sz > 0) 1289 if (mopts.malloc_junk && sz > 0)
1222 memset(p, SOME_FREEJUNK, sz); 1290 memset(p, SOME_FREEJUNK, sz);
1223 if (!malloc_freeprot) { 1291 if (!mopts.malloc_freeprot) {
1224 i = getrbyte() & (MALLOC_DELAYED_CHUNKS - 1); 1292 i = getrbyte() & (MALLOC_DELAYED_CHUNKS - 1);
1225 tmp = p; 1293 tmp = p;
1226 p = g_pool.delayed_chunks[i]; 1294 p = g_pool->delayed_chunks[i];
1227 g_pool.delayed_chunks[i] = tmp; 1295 g_pool->delayed_chunks[i] = tmp;
1228 } 1296 }
1229 if (p != NULL) { 1297 if (p != NULL) {
1230 r = find(&g_pool, p); 1298 r = find(g_pool, p);
1231 if (r == NULL) { 1299 if (r == NULL) {
1232 wrterror("bogus pointer (double free?)"); 1300 wrterror("bogus pointer (double free?)");
1233 return; 1301 return;
1234 } 1302 }
1235 free_bytes(&g_pool, r, p); 1303 free_bytes(g_pool, r, p);
1236 } 1304 }
1237 } 1305 }
1238} 1306}
@@ -1248,6 +1316,11 @@ free(void *ptr)
1248 1316
1249 _MALLOC_LOCK(); 1317 _MALLOC_LOCK();
1250 malloc_func = " in free():"; 1318 malloc_func = " in free():";
1319 if (g_pool == NULL) {
1320 _MALLOC_UNLOCK();
1321 wrterror("free() called before allocation");
1322 return;
1323 }
1251 if (malloc_active++) { 1324 if (malloc_active++) {
1252 malloc_recurse(); 1325 malloc_recurse();
1253 return; 1326 return;
@@ -1269,12 +1342,12 @@ orealloc(void *p, size_t newsz)
1269 if (p == NULL) 1342 if (p == NULL)
1270 return omalloc(newsz, 0); 1343 return omalloc(newsz, 0);
1271 1344
1272 r = find(&g_pool, p); 1345 r = find(g_pool, p);
1273 if (r == NULL) { 1346 if (r == NULL) {
1274 wrterror("bogus pointer (double free?)"); 1347 wrterror("bogus pointer (double free?)");
1275 return NULL; 1348 return NULL;
1276 } 1349 }
1277 if (newsz >= SIZE_MAX - malloc_guard - MALLOC_PAGESIZE) { 1350 if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
1278 errno = ENOMEM; 1351 errno = ENOMEM;
1279 return NULL; 1352 return NULL;
1280 } 1353 }
@@ -1282,61 +1355,63 @@ orealloc(void *p, size_t newsz)
1282 REALSIZE(oldsz, r); 1355 REALSIZE(oldsz, r);
1283 goldsz = oldsz; 1356 goldsz = oldsz;
1284 if (oldsz > MALLOC_MAXCHUNK) { 1357 if (oldsz > MALLOC_MAXCHUNK) {
1285 if (oldsz < malloc_guard) 1358 if (oldsz < mopts.malloc_guard)
1286 wrterror("guard size"); 1359 wrterror("guard size");
1287 oldsz -= malloc_guard; 1360 oldsz -= mopts.malloc_guard;
1288 } 1361 }
1289 1362
1290 gnewsz = newsz; 1363 gnewsz = newsz;
1291 if (gnewsz > MALLOC_MAXCHUNK) 1364 if (gnewsz > MALLOC_MAXCHUNK)
1292 gnewsz += malloc_guard; 1365 gnewsz += mopts.malloc_guard;
1293 1366
1294 if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p && 1367 if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p &&
1295 !malloc_realloc) { 1368 !mopts.malloc_realloc) {
1296 size_t roldsz = PAGEROUND(goldsz); 1369 size_t roldsz = PAGEROUND(goldsz);
1297 size_t rnewsz = PAGEROUND(gnewsz); 1370 size_t rnewsz = PAGEROUND(gnewsz);
1298 1371
1299 if (rnewsz > roldsz) { 1372 if (rnewsz > roldsz) {
1300 if (!malloc_guard) { 1373 if (!mopts.malloc_guard) {
1301 STATS_INC(g_pool.cheap_realloc_tries); 1374 STATS_INC(g_pool.cheap_realloc_tries);
1302 zapcacheregion(&g_pool, p + roldsz); 1375 zapcacheregion(g_pool, p + roldsz);
1303 q = MMAPA(p + roldsz, rnewsz - roldsz); 1376 q = MMAPA(p + roldsz, rnewsz - roldsz);
1304 if (q == p + roldsz) { 1377 if (q == p + roldsz) {
1305 malloc_used += rnewsz - roldsz; 1378 malloc_used += rnewsz - roldsz;
1306 if (malloc_junk) 1379 if (mopts.malloc_junk)
1307 memset(q, SOME_JUNK, 1380 memset(q, SOME_JUNK,
1308 rnewsz - roldsz); 1381 rnewsz - roldsz);
1309 r->size = newsz; 1382 r->size = newsz;
1310 STATS_INC(g_pool.cheap_reallocs); 1383 STATS_INC(g_pool->cheap_reallocs);
1311 return p; 1384 return p;
1312 } else if (q != MAP_FAILED) 1385 } else if (q != MAP_FAILED)
1313 munmap(q, rnewsz - roldsz); 1386 munmap(q, rnewsz - roldsz);
1314 } 1387 }
1315 } else if (rnewsz < roldsz) { 1388 } else if (rnewsz < roldsz) {
1316 if (malloc_guard) { 1389 if (mopts.malloc_guard) {
1317 if (mprotect((char *)p + roldsz - malloc_guard, 1390 if (mprotect((char *)p + roldsz -
1318 malloc_guard, PROT_READ | PROT_WRITE)) 1391 mopts.malloc_guard, mopts.malloc_guard,
1392 PROT_READ | PROT_WRITE))
1319 wrterror("mprotect"); 1393 wrterror("mprotect");
1320 if (mprotect((char *)p + rnewsz - malloc_guard, 1394 if (mprotect((char *)p + rnewsz -
1321 malloc_guard, PROT_NONE)) 1395 mopts.malloc_guard, mopts.malloc_guard,
1396 PROT_NONE))
1322 wrterror("mprotect"); 1397 wrterror("mprotect");
1323 } 1398 }
1324 unmap(&g_pool, (char *)p + rnewsz, roldsz - rnewsz); 1399 unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz);
1325 r->size = gnewsz; 1400 r->size = gnewsz;
1326 return p; 1401 return p;
1327 } else { 1402 } else {
1328 if (newsz > oldsz && malloc_junk) 1403 if (newsz > oldsz && mopts.malloc_junk)
1329 memset((char *)p + newsz, SOME_JUNK, 1404 memset((char *)p + newsz, SOME_JUNK,
1330 rnewsz - malloc_guard - newsz); 1405 rnewsz - mopts.malloc_guard - newsz);
1331 r->size = gnewsz; 1406 r->size = gnewsz;
1332 return p; 1407 return p;
1333 } 1408 }
1334 } 1409 }
1335 if (newsz <= oldsz && newsz > oldsz / 2 && !malloc_realloc) { 1410 if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) {
1336 if (malloc_junk && newsz > 0) 1411 if (mopts.malloc_junk && newsz > 0)
1337 memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); 1412 memset((char *)p + newsz, SOME_JUNK, oldsz - newsz);
1338 return p; 1413 return p;
1339 } else if (newsz != oldsz || malloc_realloc) { 1414 } else if (newsz != oldsz || mopts.malloc_realloc) {
1340 q = omalloc(newsz, 0); 1415 q = omalloc(newsz, 0);
1341 if (q == NULL) 1416 if (q == NULL)
1342 return NULL; 1417 return NULL;
@@ -1356,25 +1431,19 @@ realloc(void *ptr, size_t size)
1356 1431
1357 _MALLOC_LOCK(); 1432 _MALLOC_LOCK();
1358 malloc_func = " in realloc():"; 1433 malloc_func = " in realloc():";
1359 if (!g_pool.regions_total) { 1434 if (g_pool == NULL) {
1360 if (omalloc_init(&g_pool)) { 1435 if (malloc_init() != 0)
1361 _MALLOC_UNLOCK();
1362 if (malloc_xmalloc)
1363 wrterror("out of memory");
1364 errno = ENOMEM;
1365 return NULL; 1436 return NULL;
1366 }
1367 } 1437 }
1368 if (malloc_active++) { 1438 if (malloc_active++) {
1369 malloc_recurse(); 1439 malloc_recurse();
1370 return NULL; 1440 return NULL;
1371 } 1441 }
1372
1373 r = orealloc(ptr, size); 1442 r = orealloc(ptr, size);
1374 1443
1375 malloc_active--; 1444 malloc_active--;
1376 _MALLOC_UNLOCK(); 1445 _MALLOC_UNLOCK();
1377 if (r == NULL && malloc_xmalloc) { 1446 if (r == NULL && mopts.malloc_xmalloc) {
1378 wrterror("out of memory"); 1447 wrterror("out of memory");
1379 errno = ENOMEM; 1448 errno = ENOMEM;
1380 } 1449 }
@@ -1394,19 +1463,14 @@ calloc(size_t nmemb, size_t size)
1394 1463
1395 _MALLOC_LOCK(); 1464 _MALLOC_LOCK();
1396 malloc_func = " in calloc():"; 1465 malloc_func = " in calloc():";
1397 if (!g_pool.regions_total) { 1466 if (g_pool == NULL) {
1398 if (omalloc_init(&g_pool)) { 1467 if (malloc_init() != 0)
1399 _MALLOC_UNLOCK();
1400 if (malloc_xmalloc)
1401 wrterror("out of memory");
1402 errno = ENOMEM;
1403 return NULL; 1468 return NULL;
1404 }
1405 } 1469 }
1406 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 1470 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1407 nmemb > 0 && SIZE_MAX / nmemb < size) { 1471 nmemb > 0 && SIZE_MAX / nmemb < size) {
1408 _MALLOC_UNLOCK(); 1472 _MALLOC_UNLOCK();
1409 if (malloc_xmalloc) 1473 if (mopts.malloc_xmalloc)
1410 wrterror("out of memory"); 1474 wrterror("out of memory");
1411 errno = ENOMEM; 1475 errno = ENOMEM;
1412 return NULL; 1476 return NULL;
@@ -1422,7 +1486,7 @@ calloc(size_t nmemb, size_t size)
1422 1486
1423 malloc_active--; 1487 malloc_active--;
1424 _MALLOC_UNLOCK(); 1488 _MALLOC_UNLOCK();
1425 if (r == NULL && malloc_xmalloc) { 1489 if (r == NULL && mopts.malloc_xmalloc) {
1426 wrterror("out of memory"); 1490 wrterror("out of memory");
1427 errno = ENOMEM; 1491 errno = ENOMEM;
1428 } 1492 }
@@ -1430,3 +1494,4 @@ calloc(size_t nmemb, size_t size)
1430 errno = saved_errno; 1494 errno = saved_errno;
1431 return r; 1495 return r;
1432} 1496}
1497