diff options
| author | otto <> | 2019-05-10 15:03:24 +0000 |
|---|---|---|
| committer | otto <> | 2019-05-10 15:03:24 +0000 |
| commit | 5110d9a926df971b8571a962d563e7d569b505d7 (patch) | |
| tree | 351f341ee663baddfeb4c10cfa7273013fe52ddd /src/lib/libc/stdlib/malloc.c | |
| parent | cf957dfd1597d2bc3d519eb9ee762912ca2d03a2 (diff) | |
| download | openbsd-5110d9a926df971b8571a962d563e7d569b505d7.tar.gz openbsd-5110d9a926df971b8571a962d563e7d569b505d7.tar.bz2 openbsd-5110d9a926df971b8571a962d563e7d569b505d7.zip | |
Inroduce malloc_conceal() and calloc_conceal(). Similar to their
counterparts but return memory in pages marked MAP_CONCEAL and on
free() freezero() is actually called.
Diffstat (limited to 'src/lib/libc/stdlib/malloc.c')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 389 |
1 files changed, 193 insertions, 196 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index e41178d5c5..ff41f61385 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.259 2019/01/10 18:47:05 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.260 2019/05/10 15:03:24 otto Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net> | 3 | * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net> |
| 4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> | 4 | * Copyright (c) 2012 Matthew Dempsky <matthew@openbsd.org> |
| @@ -90,17 +90,17 @@ | |||
| 90 | #define SOME_JUNK 0xdb /* deadbeef */ | 90 | #define SOME_JUNK 0xdb /* deadbeef */ |
| 91 | #define SOME_FREEJUNK 0xdf /* dead, free */ | 91 | #define SOME_FREEJUNK 0xdf /* dead, free */ |
| 92 | 92 | ||
| 93 | #define MMAP(sz) mmap(NULL, (sz), PROT_READ | PROT_WRITE, \ | 93 | #define MMAP(sz,f) mmap(NULL, (sz), PROT_READ | PROT_WRITE, \ |
| 94 | MAP_ANON | MAP_PRIVATE, -1, 0) | 94 | MAP_ANON | MAP_PRIVATE | (f), -1, 0) |
| 95 | 95 | ||
| 96 | #define MMAPNONE(sz) mmap(NULL, (sz), PROT_NONE, \ | 96 | #define MMAPNONE(sz,f) mmap(NULL, (sz), PROT_NONE, \ |
| 97 | MAP_ANON | MAP_PRIVATE, -1, 0) | 97 | MAP_ANON | MAP_PRIVATE | (f), -1, 0) |
| 98 | 98 | ||
| 99 | #define MMAPA(a,sz) mmap((a), (sz), PROT_READ | PROT_WRITE, \ | 99 | #define MMAPA(a,sz,f) mmap((a), (sz), PROT_READ | PROT_WRITE, \ |
| 100 | MAP_ANON | MAP_PRIVATE, -1, 0) | 100 | MAP_ANON | MAP_PRIVATE | (f), -1, 0) |
| 101 | 101 | ||
| 102 | #define MQUERY(a, sz) mquery((a), (sz), PROT_READ | PROT_WRITE, \ | 102 | #define MQUERY(a,sz,f) mquery((a), (sz), PROT_READ | PROT_WRITE, \ |
| 103 | MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) | 103 | MAP_ANON | MAP_PRIVATE | MAP_FIXED | (f), -1, 0) |
| 104 | 104 | ||
| 105 | struct region_info { | 105 | struct region_info { |
| 106 | void *p; /* page; low bits used to mark chunks */ | 106 | void *p; /* page; low bits used to mark chunks */ |
| @@ -118,19 +118,22 @@ struct dir_info { | |||
| 118 | struct region_info *r; /* region slots */ | 118 | struct region_info *r; /* region slots */ |
| 119 | size_t regions_total; /* number of region slots */ | 119 | size_t regions_total; /* number of region slots */ |
| 120 | size_t regions_free; /* number of free slots */ | 120 | size_t regions_free; /* number of free slots */ |
| 121 | size_t free_regions_size; /* free pages cached */ | ||
| 122 | size_t rbytesused; /* random bytes used */ | ||
| 123 | char *func; /* current function */ | ||
| 124 | u_int malloc_cache; /* # of free pages we cache */ | ||
| 125 | int malloc_junk; /* junk fill? */ | ||
| 126 | int mmap_flag; /* extra flag for mmap */ | ||
| 127 | u_int rotor; | ||
| 128 | int mutex; | ||
| 121 | /* lists of free chunk info structs */ | 129 | /* lists of free chunk info structs */ |
| 122 | struct chunk_head chunk_info_list[MALLOC_MAXSHIFT + 1]; | 130 | struct chunk_head chunk_info_list[MALLOC_MAXSHIFT + 1]; |
| 123 | /* lists of chunks with free slots */ | 131 | /* lists of chunks with free slots */ |
| 124 | struct chunk_head chunk_dir[MALLOC_MAXSHIFT + 1][MALLOC_CHUNK_LISTS]; | 132 | struct chunk_head chunk_dir[MALLOC_MAXSHIFT + 1][MALLOC_CHUNK_LISTS]; |
| 125 | size_t free_regions_size; /* free pages cached */ | ||
| 126 | /* free pages cache */ | 133 | /* free pages cache */ |
| 127 | struct region_info free_regions[MALLOC_MAXCACHE]; | 134 | struct region_info free_regions[MALLOC_MAXCACHE]; |
| 128 | /* delayed free chunk slots */ | 135 | /* delayed free chunk slots */ |
| 129 | u_int rotor; | ||
| 130 | void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1]; | 136 | void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1]; |
| 131 | size_t rbytesused; /* random bytes used */ | ||
| 132 | char *func; /* current function */ | ||
| 133 | int mutex; | ||
| 134 | u_char rbytes[32]; /* random bytes */ | 137 | u_char rbytes[32]; /* random bytes */ |
| 135 | #ifdef MALLOC_STATS | 138 | #ifdef MALLOC_STATS |
| 136 | size_t inserts; | 139 | size_t inserts; |
| @@ -187,12 +190,12 @@ struct malloc_readonly { | |||
| 187 | int malloc_mt; /* multi-threaded mode? */ | 190 | int malloc_mt; /* multi-threaded mode? */ |
| 188 | int malloc_freecheck; /* Extensive double free check */ | 191 | int malloc_freecheck; /* Extensive double free check */ |
| 189 | int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ | 192 | int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ |
| 190 | int malloc_junk; /* junk fill? */ | 193 | int def_malloc_junk; /* junk fill? */ |
| 191 | int malloc_realloc; /* always realloc? */ | 194 | int malloc_realloc; /* always realloc? */ |
| 192 | int malloc_xmalloc; /* xmalloc behaviour? */ | 195 | int malloc_xmalloc; /* xmalloc behaviour? */ |
| 193 | int chunk_canaries; /* use canaries after chunks? */ | 196 | int chunk_canaries; /* use canaries after chunks? */ |
| 194 | int internal_funcs; /* use better recallocarray/freezero? */ | 197 | int internal_funcs; /* use better recallocarray/freezero? */ |
| 195 | u_int malloc_cache; /* free pages we cache */ | 198 | u_int def_malloc_cache; /* free pages we cache */ |
| 196 | size_t malloc_guard; /* use guard pages after allocations? */ | 199 | size_t malloc_guard; /* use guard pages after allocations? */ |
| 197 | #ifdef MALLOC_STATS | 200 | #ifdef MALLOC_STATS |
| 198 | int malloc_stats; /* dump statistics at end */ | 201 | int malloc_stats; /* dump statistics at end */ |
| @@ -268,9 +271,9 @@ static inline struct dir_info * | |||
| 268 | getpool(void) | 271 | getpool(void) |
| 269 | { | 272 | { |
| 270 | if (!mopts.malloc_mt) | 273 | if (!mopts.malloc_mt) |
| 271 | return mopts.malloc_pool[0]; | 274 | return mopts.malloc_pool[1]; |
| 272 | else | 275 | else /* first one reserved for special pool */ |
| 273 | return mopts.malloc_pool[TIB_GET()->tib_tid & | 276 | return mopts.malloc_pool[1 + TIB_GET()->tib_tid % |
| 274 | (mopts.malloc_mutexes - 1)]; | 277 | (mopts.malloc_mutexes - 1)]; |
| 275 | } | 278 | } |
| 276 | 279 | ||
| @@ -327,16 +330,16 @@ omalloc_parseopt(char opt) | |||
| 327 | break; | 330 | break; |
| 328 | case '-': | 331 | case '-': |
| 329 | mopts.malloc_mutexes >>= 1; | 332 | mopts.malloc_mutexes >>= 1; |
| 330 | if (mopts.malloc_mutexes < 1) | 333 | if (mopts.malloc_mutexes < 2) |
| 331 | mopts.malloc_mutexes = 1; | 334 | mopts.malloc_mutexes = 2; |
| 332 | break; | 335 | break; |
| 333 | case '>': | 336 | case '>': |
| 334 | mopts.malloc_cache <<= 1; | 337 | mopts.def_malloc_cache <<= 1; |
| 335 | if (mopts.malloc_cache > MALLOC_MAXCACHE) | 338 | if (mopts.def_malloc_cache > MALLOC_MAXCACHE) |
| 336 | mopts.malloc_cache = MALLOC_MAXCACHE; | 339 | mopts.def_malloc_cache = MALLOC_MAXCACHE; |
| 337 | break; | 340 | break; |
| 338 | case '<': | 341 | case '<': |
| 339 | mopts.malloc_cache >>= 1; | 342 | mopts.def_malloc_cache >>= 1; |
| 340 | break; | 343 | break; |
| 341 | case 'c': | 344 | case 'c': |
| 342 | mopts.chunk_canaries = 0; | 345 | mopts.chunk_canaries = 0; |
| @@ -367,12 +370,12 @@ omalloc_parseopt(char opt) | |||
| 367 | mopts.malloc_guard = MALLOC_PAGESIZE; | 370 | mopts.malloc_guard = MALLOC_PAGESIZE; |
| 368 | break; | 371 | break; |
| 369 | case 'j': | 372 | case 'j': |
| 370 | if (mopts.malloc_junk > 0) | 373 | if (mopts.def_malloc_junk > 0) |
| 371 | mopts.malloc_junk--; | 374 | mopts.def_malloc_junk--; |
| 372 | break; | 375 | break; |
| 373 | case 'J': | 376 | case 'J': |
| 374 | if (mopts.malloc_junk < 2) | 377 | if (mopts.def_malloc_junk < 2) |
| 375 | mopts.malloc_junk++; | 378 | mopts.def_malloc_junk++; |
| 376 | break; | 379 | break; |
| 377 | case 'r': | 380 | case 'r': |
| 378 | mopts.malloc_realloc = 0; | 381 | mopts.malloc_realloc = 0; |
| @@ -410,8 +413,8 @@ omalloc_init(void) | |||
| 410 | * Default options | 413 | * Default options |
| 411 | */ | 414 | */ |
| 412 | mopts.malloc_mutexes = 8; | 415 | mopts.malloc_mutexes = 8; |
| 413 | mopts.malloc_junk = 1; | 416 | mopts.def_malloc_junk = 1; |
| 414 | mopts.malloc_cache = MALLOC_DEFAULT_CACHE; | 417 | mopts.def_malloc_cache = MALLOC_DEFAULT_CACHE; |
| 415 | 418 | ||
| 416 | for (i = 0; i < 3; i++) { | 419 | for (i = 0; i < 3; i++) { |
| 417 | switch (i) { | 420 | switch (i) { |
| @@ -442,12 +445,12 @@ omalloc_init(void) | |||
| 442 | case 'S': | 445 | case 'S': |
| 443 | for (q = "CFGJ"; *q != '\0'; q++) | 446 | for (q = "CFGJ"; *q != '\0'; q++) |
| 444 | omalloc_parseopt(*q); | 447 | omalloc_parseopt(*q); |
| 445 | mopts.malloc_cache = 0; | 448 | mopts.def_malloc_cache = 0; |
| 446 | break; | 449 | break; |
| 447 | case 's': | 450 | case 's': |
| 448 | for (q = "cfgj"; *q != '\0'; q++) | 451 | for (q = "cfgj"; *q != '\0'; q++) |
| 449 | omalloc_parseopt(*q); | 452 | omalloc_parseopt(*q); |
| 450 | mopts.malloc_cache = MALLOC_DEFAULT_CACHE; | 453 | mopts.def_malloc_cache = MALLOC_DEFAULT_CACHE; |
| 451 | break; | 454 | break; |
| 452 | default: | 455 | default: |
| 453 | omalloc_parseopt(*p); | 456 | omalloc_parseopt(*p); |
| @@ -468,7 +471,7 @@ omalloc_init(void) | |||
| 468 | } | 471 | } |
| 469 | 472 | ||
| 470 | static void | 473 | static void |
| 471 | omalloc_poolinit(struct dir_info **dp) | 474 | omalloc_poolinit(struct dir_info **dp, int mmap_flag) |
| 472 | { | 475 | { |
| 473 | char *p; | 476 | char *p; |
| 474 | size_t d_avail, regioninfo_size; | 477 | size_t d_avail, regioninfo_size; |
| @@ -480,7 +483,8 @@ omalloc_poolinit(struct dir_info **dp) | |||
| 480 | * randomise offset inside the page at which the dir_info | 483 | * randomise offset inside the page at which the dir_info |
| 481 | * lies (subject to alignment by 1 << MALLOC_MINSHIFT) | 484 | * lies (subject to alignment by 1 << MALLOC_MINSHIFT) |
| 482 | */ | 485 | */ |
| 483 | if ((p = MMAPNONE(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED) | 486 | if ((p = MMAPNONE(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2), mmap_flag)) == |
| 487 | MAP_FAILED) | ||
| 484 | wrterror(NULL, "malloc init mmap failed"); | 488 | wrterror(NULL, "malloc init mmap failed"); |
| 485 | mprotect(p + MALLOC_PAGESIZE, DIR_INFO_RSZ, PROT_READ | PROT_WRITE); | 489 | mprotect(p + MALLOC_PAGESIZE, DIR_INFO_RSZ, PROT_READ | PROT_WRITE); |
| 486 | d_avail = (DIR_INFO_RSZ - sizeof(*d)) >> MALLOC_MINSHIFT; | 490 | d_avail = (DIR_INFO_RSZ - sizeof(*d)) >> MALLOC_MINSHIFT; |
| @@ -490,7 +494,7 @@ omalloc_poolinit(struct dir_info **dp) | |||
| 490 | rbytes_init(d); | 494 | rbytes_init(d); |
| 491 | d->regions_free = d->regions_total = MALLOC_INITIAL_REGIONS; | 495 | d->regions_free = d->regions_total = MALLOC_INITIAL_REGIONS; |
| 492 | regioninfo_size = d->regions_total * sizeof(struct region_info); | 496 | regioninfo_size = d->regions_total * sizeof(struct region_info); |
| 493 | d->r = MMAP(regioninfo_size); | 497 | d->r = MMAP(regioninfo_size, mmap_flag); |
| 494 | if (d->r == MAP_FAILED) { | 498 | if (d->r == MAP_FAILED) { |
| 495 | d->regions_total = 0; | 499 | d->regions_total = 0; |
| 496 | wrterror(NULL, "malloc init mmap failed"); | 500 | wrterror(NULL, "malloc init mmap failed"); |
| @@ -501,6 +505,9 @@ omalloc_poolinit(struct dir_info **dp) | |||
| 501 | LIST_INIT(&d->chunk_dir[i][j]); | 505 | LIST_INIT(&d->chunk_dir[i][j]); |
| 502 | } | 506 | } |
| 503 | STATS_ADD(d->malloc_used, regioninfo_size + 3 * MALLOC_PAGESIZE); | 507 | STATS_ADD(d->malloc_used, regioninfo_size + 3 * MALLOC_PAGESIZE); |
| 508 | d->mmap_flag = mmap_flag; | ||
| 509 | d->malloc_junk = mopts.def_malloc_junk; | ||
| 510 | d->malloc_cache = mopts.def_malloc_cache; | ||
| 504 | d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d; | 511 | d->canary1 = mopts.malloc_canary ^ (u_int32_t)(uintptr_t)d; |
| 505 | d->canary2 = ~d->canary1; | 512 | d->canary2 = ~d->canary1; |
| 506 | 513 | ||
| @@ -523,7 +530,7 @@ omalloc_grow(struct dir_info *d) | |||
| 523 | newsize = newtotal * sizeof(struct region_info); | 530 | newsize = newtotal * sizeof(struct region_info); |
| 524 | mask = newtotal - 1; | 531 | mask = newtotal - 1; |
| 525 | 532 | ||
| 526 | p = MMAP(newsize); | 533 | p = MMAP(newsize, d->mmap_flag); |
| 527 | if (p == MAP_FAILED) | 534 | if (p == MAP_FAILED) |
| 528 | return 1; | 535 | return 1; |
| 529 | 536 | ||
| @@ -662,14 +669,14 @@ unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk) | |||
| 662 | if (sz != PAGEROUND(sz)) | 669 | if (sz != PAGEROUND(sz)) |
| 663 | wrterror(d, "munmap round"); | 670 | wrterror(d, "munmap round"); |
| 664 | 671 | ||
| 665 | rsz = mopts.malloc_cache - d->free_regions_size; | 672 | rsz = d->malloc_cache - d->free_regions_size; |
| 666 | 673 | ||
| 667 | /* | 674 | /* |
| 668 | * normally the cache holds recently freed regions, but if the region | 675 | * normally the cache holds recently freed regions, but if the region |
| 669 | * to unmap is larger than the cache size or we're clearing and the | 676 | * to unmap is larger than the cache size or we're clearing and the |
| 670 | * cache is full, just munmap | 677 | * cache is full, just munmap |
| 671 | */ | 678 | */ |
| 672 | if (psz > mopts.malloc_cache || (clear > 0 && rsz == 0)) { | 679 | if (psz > d->malloc_cache || (clear > 0 && rsz == 0)) { |
| 673 | i = munmap(p, sz); | 680 | i = munmap(p, sz); |
| 674 | if (i) | 681 | if (i) |
| 675 | wrterror(d, "munmap %p", p); | 682 | wrterror(d, "munmap %p", p); |
| @@ -677,7 +684,7 @@ unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk) | |||
| 677 | return; | 684 | return; |
| 678 | } | 685 | } |
| 679 | offset = getrbyte(d); | 686 | offset = getrbyte(d); |
| 680 | mask = mopts.malloc_cache - 1; | 687 | mask = d->malloc_cache - 1; |
| 681 | if (psz > rsz) { | 688 | if (psz > rsz) { |
| 682 | size_t tounmap = psz - rsz; | 689 | size_t tounmap = psz - rsz; |
| 683 | for (i = 0; ; i++) { | 690 | for (i = 0; ; i++) { |
| @@ -717,7 +724,7 @@ unmap(struct dir_info *d, void *p, size_t sz, size_t clear, int junk) | |||
| 717 | break; | 724 | break; |
| 718 | } | 725 | } |
| 719 | } | 726 | } |
| 720 | if (d->free_regions_size > mopts.malloc_cache) | 727 | if (d->free_regions_size > d->malloc_cache) |
| 721 | wrterror(d, "malloc cache overflow"); | 728 | wrterror(d, "malloc cache overflow"); |
| 722 | } | 729 | } |
| 723 | 730 | ||
| @@ -728,7 +735,7 @@ zapcacheregion(struct dir_info *d, void *p, size_t len) | |||
| 728 | struct region_info *r; | 735 | struct region_info *r; |
| 729 | size_t rsz; | 736 | size_t rsz; |
| 730 | 737 | ||
| 731 | for (i = 0; i < mopts.malloc_cache; i++) { | 738 | for (i = 0; i < d->malloc_cache; i++) { |
| 732 | r = &d->free_regions[i]; | 739 | r = &d->free_regions[i]; |
| 733 | if (r->p >= p && r->p <= (void *)((char *)p + len)) { | 740 | if (r->p >= p && r->p <= (void *)((char *)p + len)) { |
| 734 | rsz = r->size << MALLOC_PAGESHIFT; | 741 | rsz = r->size << MALLOC_PAGESHIFT; |
| @@ -757,15 +764,15 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) | |||
| 757 | 764 | ||
| 758 | if (hint == NULL && psz > d->free_regions_size) { | 765 | if (hint == NULL && psz > d->free_regions_size) { |
| 759 | _MALLOC_LEAVE(d); | 766 | _MALLOC_LEAVE(d); |
| 760 | p = MMAP(sz); | 767 | p = MMAP(sz, d->mmap_flag); |
| 761 | _MALLOC_ENTER(d); | 768 | _MALLOC_ENTER(d); |
| 762 | if (p != MAP_FAILED) | 769 | if (p != MAP_FAILED) |
| 763 | STATS_ADD(d->malloc_used, sz); | 770 | STATS_ADD(d->malloc_used, sz); |
| 764 | /* zero fill not needed */ | 771 | /* zero fill not needed */ |
| 765 | return p; | 772 | return p; |
| 766 | } | 773 | } |
| 767 | for (i = 0; i < mopts.malloc_cache; i++) { | 774 | for (i = 0; i < d->malloc_cache; i++) { |
| 768 | r = &d->free_regions[(i + d->rotor) & (mopts.malloc_cache - 1)]; | 775 | r = &d->free_regions[(i + d->rotor) & (d->malloc_cache - 1)]; |
| 769 | if (r->p != NULL) { | 776 | if (r->p != NULL) { |
| 770 | if (hint != NULL && r->p != hint) | 777 | if (hint != NULL && r->p != hint) |
| 771 | continue; | 778 | continue; |
| @@ -777,7 +784,7 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) | |||
| 777 | mprotect(p, sz, PROT_READ | PROT_WRITE); | 784 | mprotect(p, sz, PROT_READ | PROT_WRITE); |
| 778 | if (zero_fill) | 785 | if (zero_fill) |
| 779 | memset(p, 0, sz); | 786 | memset(p, 0, sz); |
| 780 | else if (mopts.malloc_junk == 2 && | 787 | else if (d->malloc_junk == 2 && |
| 781 | mopts.malloc_freeunmap) | 788 | mopts.malloc_freeunmap) |
| 782 | memset(p, SOME_FREEJUNK, sz); | 789 | memset(p, SOME_FREEJUNK, sz); |
| 783 | d->rotor += i + 1; | 790 | d->rotor += i + 1; |
| @@ -796,16 +803,16 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) | |||
| 796 | d->free_regions_size -= psz; | 803 | d->free_regions_size -= psz; |
| 797 | if (zero_fill) | 804 | if (zero_fill) |
| 798 | memset(p, 0, sz); | 805 | memset(p, 0, sz); |
| 799 | else if (mopts.malloc_junk == 2 && mopts.malloc_freeunmap) | 806 | else if (d->malloc_junk == 2 && mopts.malloc_freeunmap) |
| 800 | memset(p, SOME_FREEJUNK, sz); | 807 | memset(p, SOME_FREEJUNK, sz); |
| 801 | return p; | 808 | return p; |
| 802 | } | 809 | } |
| 803 | if (hint != NULL) | 810 | if (hint != NULL) |
| 804 | return MAP_FAILED; | 811 | return MAP_FAILED; |
| 805 | if (d->free_regions_size > mopts.malloc_cache) | 812 | if (d->free_regions_size > d->malloc_cache) |
| 806 | wrterror(d, "malloc cache"); | 813 | wrterror(d, "malloc cache"); |
| 807 | _MALLOC_LEAVE(d); | 814 | _MALLOC_LEAVE(d); |
| 808 | p = MMAP(sz); | 815 | p = MMAP(sz, d->mmap_flag); |
| 809 | _MALLOC_ENTER(d); | 816 | _MALLOC_ENTER(d); |
| 810 | if (p != MAP_FAILED) | 817 | if (p != MAP_FAILED) |
| 811 | STATS_ADD(d->malloc_used, sz); | 818 | STATS_ADD(d->malloc_used, sz); |
| @@ -857,7 +864,7 @@ alloc_chunk_info(struct dir_info *d, int bits) | |||
| 857 | size += count * sizeof(u_short); | 864 | size += count * sizeof(u_short); |
| 858 | size = _ALIGN(size); | 865 | size = _ALIGN(size); |
| 859 | 866 | ||
| 860 | q = MMAP(MALLOC_PAGESIZE); | 867 | q = MMAP(MALLOC_PAGESIZE, d->mmap_flag); |
| 861 | if (q == MAP_FAILED) | 868 | if (q == MAP_FAILED) |
| 862 | return NULL; | 869 | return NULL; |
| 863 | STATS_ADD(d->malloc_used, MALLOC_PAGESIZE); | 870 | STATS_ADD(d->malloc_used, MALLOC_PAGESIZE); |
| @@ -905,7 +912,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum) | |||
| 905 | return bp; | 912 | return bp; |
| 906 | 913 | ||
| 907 | err: | 914 | err: |
| 908 | unmap(d, pp, MALLOC_PAGESIZE, 0, mopts.malloc_junk); | 915 | unmap(d, pp, MALLOC_PAGESIZE, 0, d->malloc_junk); |
| 909 | return NULL; | 916 | return NULL; |
| 910 | } | 917 | } |
| 911 | 918 | ||
| @@ -1016,7 +1023,7 @@ found: | |||
| 1016 | 1023 | ||
| 1017 | p = (char *)bp->page + k; | 1024 | p = (char *)bp->page + k; |
| 1018 | if (bp->size > 0) { | 1025 | if (bp->size > 0) { |
| 1019 | if (mopts.malloc_junk == 2) | 1026 | if (d->malloc_junk == 2) |
| 1020 | memset(p, SOME_JUNK, bp->size); | 1027 | memset(p, SOME_JUNK, bp->size); |
| 1021 | else if (mopts.chunk_canaries) | 1028 | else if (mopts.chunk_canaries) |
| 1022 | fill_canary(p, size, bp->size); | 1029 | fill_canary(p, size, bp->size); |
| @@ -1148,15 +1155,15 @@ omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f) | |||
| 1148 | 1155 | ||
| 1149 | if (MALLOC_MOVE_COND(sz)) { | 1156 | if (MALLOC_MOVE_COND(sz)) { |
| 1150 | /* fill whole allocation */ | 1157 | /* fill whole allocation */ |
| 1151 | if (mopts.malloc_junk == 2) | 1158 | if (pool->malloc_junk == 2) |
| 1152 | memset(p, SOME_JUNK, psz - mopts.malloc_guard); | 1159 | memset(p, SOME_JUNK, psz - mopts.malloc_guard); |
| 1153 | /* shift towards the end */ | 1160 | /* shift towards the end */ |
| 1154 | p = MALLOC_MOVE(p, sz); | 1161 | p = MALLOC_MOVE(p, sz); |
| 1155 | /* fill zeros if needed and overwritten above */ | 1162 | /* fill zeros if needed and overwritten above */ |
| 1156 | if (zero_fill && mopts.malloc_junk == 2) | 1163 | if (zero_fill && pool->malloc_junk == 2) |
| 1157 | memset(p, 0, sz - mopts.malloc_guard); | 1164 | memset(p, 0, sz - mopts.malloc_guard); |
| 1158 | } else { | 1165 | } else { |
| 1159 | if (mopts.malloc_junk == 2) { | 1166 | if (pool->malloc_junk == 2) { |
| 1160 | if (zero_fill) | 1167 | if (zero_fill) |
| 1161 | memset((char *)p + sz - mopts.malloc_guard, | 1168 | memset((char *)p + sz - mopts.malloc_guard, |
| 1162 | SOME_JUNK, psz - sz); | 1169 | SOME_JUNK, psz - sz); |
| @@ -1200,25 +1207,33 @@ malloc_recurse(struct dir_info *d) | |||
| 1200 | void | 1207 | void |
| 1201 | _malloc_init(int from_rthreads) | 1208 | _malloc_init(int from_rthreads) |
| 1202 | { | 1209 | { |
| 1203 | int i, max; | 1210 | u_int i, nmutexes; |
| 1204 | struct dir_info *d; | 1211 | struct dir_info *d; |
| 1205 | 1212 | ||
| 1206 | _MALLOC_LOCK(0); | 1213 | _MALLOC_LOCK(1); |
| 1207 | if (!from_rthreads && mopts.malloc_pool[0]) { | 1214 | if (!from_rthreads && mopts.malloc_pool[1]) { |
| 1208 | _MALLOC_UNLOCK(0); | 1215 | _MALLOC_UNLOCK(1); |
| 1209 | return; | 1216 | return; |
| 1210 | } | 1217 | } |
| 1211 | if (!mopts.malloc_canary) | 1218 | if (!mopts.malloc_canary) |
| 1212 | omalloc_init(); | 1219 | omalloc_init(); |
| 1213 | 1220 | ||
| 1214 | max = from_rthreads ? mopts.malloc_mutexes : 1; | 1221 | nmutexes = from_rthreads ? mopts.malloc_mutexes : 2; |
| 1215 | if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) | 1222 | if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) |
| 1216 | mprotect(&malloc_readonly, sizeof(malloc_readonly), | 1223 | mprotect(&malloc_readonly, sizeof(malloc_readonly), |
| 1217 | PROT_READ | PROT_WRITE); | 1224 | PROT_READ | PROT_WRITE); |
| 1218 | for (i = 0; i < max; i++) { | 1225 | for (i = 0; i < nmutexes; i++) { |
| 1219 | if (mopts.malloc_pool[i]) | 1226 | if (mopts.malloc_pool[i]) |
| 1220 | continue; | 1227 | continue; |
| 1221 | omalloc_poolinit(&d); | 1228 | if (i == 0) { |
| 1229 | omalloc_poolinit(&d, MAP_CONCEAL); | ||
| 1230 | d->malloc_junk = 2; | ||
| 1231 | d->malloc_cache = 0; | ||
| 1232 | } else { | ||
| 1233 | omalloc_poolinit(&d, 0); | ||
| 1234 | d->malloc_junk = mopts.def_malloc_junk; | ||
| 1235 | d->malloc_cache = mopts.def_malloc_cache; | ||
| 1236 | } | ||
| 1222 | d->mutex = i; | 1237 | d->mutex = i; |
| 1223 | mopts.malloc_pool[i] = d; | 1238 | mopts.malloc_pool[i] = d; |
| 1224 | } | 1239 | } |
| @@ -1234,10 +1249,31 @@ _malloc_init(int from_rthreads) | |||
| 1234 | */ | 1249 | */ |
| 1235 | if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) | 1250 | if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0) |
| 1236 | mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ); | 1251 | mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ); |
| 1237 | _MALLOC_UNLOCK(0); | 1252 | _MALLOC_UNLOCK(1); |
| 1238 | } | 1253 | } |
| 1239 | DEF_STRONG(_malloc_init); | 1254 | DEF_STRONG(_malloc_init); |
| 1240 | 1255 | ||
| 1256 | #define PROLOGUE(p, fn) \ | ||
| 1257 | d = (p); \ | ||
| 1258 | if (d == NULL) { \ | ||
| 1259 | _malloc_init(0); \ | ||
| 1260 | d = (p); \ | ||
| 1261 | } \ | ||
| 1262 | _MALLOC_LOCK(d->mutex); \ | ||
| 1263 | d->func = fn; \ | ||
| 1264 | if (d->active++) { \ | ||
| 1265 | malloc_recurse(d); \ | ||
| 1266 | return NULL; \ | ||
| 1267 | } \ | ||
| 1268 | |||
| 1269 | #define EPILOGUE() \ | ||
| 1270 | d->active--; \ | ||
| 1271 | _MALLOC_UNLOCK(d->mutex); \ | ||
| 1272 | if (r == NULL && mopts.malloc_xmalloc) \ | ||
| 1273 | wrterror(d, "out of memory"); \ | ||
| 1274 | if (r != NULL) \ | ||
| 1275 | errno = saved_errno; \ | ||
| 1276 | |||
| 1241 | void * | 1277 | void * |
| 1242 | malloc(size_t size) | 1278 | malloc(size_t size) |
| 1243 | { | 1279 | { |
| @@ -1245,29 +1281,27 @@ malloc(size_t size) | |||
| 1245 | struct dir_info *d; | 1281 | struct dir_info *d; |
| 1246 | int saved_errno = errno; | 1282 | int saved_errno = errno; |
| 1247 | 1283 | ||
| 1248 | d = getpool(); | 1284 | PROLOGUE(getpool(), "malloc") |
| 1249 | if (d == NULL) { | ||
| 1250 | _malloc_init(0); | ||
| 1251 | d = getpool(); | ||
| 1252 | } | ||
| 1253 | _MALLOC_LOCK(d->mutex); | ||
| 1254 | d->func = "malloc"; | ||
| 1255 | |||
| 1256 | if (d->active++) { | ||
| 1257 | malloc_recurse(d); | ||
| 1258 | return NULL; | ||
| 1259 | } | ||
| 1260 | r = omalloc(d, size, 0, CALLER); | 1285 | r = omalloc(d, size, 0, CALLER); |
| 1261 | d->active--; | 1286 | EPILOGUE() |
| 1262 | _MALLOC_UNLOCK(d->mutex); | ||
| 1263 | if (r == NULL && mopts.malloc_xmalloc) | ||
| 1264 | wrterror(d, "out of memory"); | ||
| 1265 | if (r != NULL) | ||
| 1266 | errno = saved_errno; | ||
| 1267 | return r; | 1287 | return r; |
| 1268 | } | 1288 | } |
| 1269 | /*DEF_STRONG(malloc);*/ | 1289 | /*DEF_STRONG(malloc);*/ |
| 1270 | 1290 | ||
| 1291 | void * | ||
| 1292 | malloc_conceal(size_t size) | ||
| 1293 | { | ||
| 1294 | void *r; | ||
| 1295 | struct dir_info *d; | ||
| 1296 | int saved_errno = errno; | ||
| 1297 | |||
| 1298 | PROLOGUE(mopts.malloc_pool[0], "malloc_conceal") | ||
| 1299 | r = omalloc(d, size, 0, CALLER); | ||
| 1300 | EPILOGUE() | ||
| 1301 | return r; | ||
| 1302 | } | ||
| 1303 | DEF_WEAK(malloc_conceal); | ||
| 1304 | |||
| 1271 | static void | 1305 | static void |
| 1272 | validate_junk(struct dir_info *pool, void *p) | 1306 | validate_junk(struct dir_info *pool, void *p) |
| 1273 | { | 1307 | { |
| @@ -1298,25 +1332,23 @@ findpool(void *p, struct dir_info *argpool, struct dir_info **foundpool, | |||
| 1298 | 1332 | ||
| 1299 | STATS_INC(pool->pool_searches); | 1333 | STATS_INC(pool->pool_searches); |
| 1300 | if (r == NULL) { | 1334 | if (r == NULL) { |
| 1301 | if (mopts.malloc_mt) { | 1335 | u_int i, nmutexes; |
| 1302 | int i; | 1336 | |
| 1303 | 1337 | nmutexes = mopts.malloc_mt ? mopts.malloc_mutexes : 2; | |
| 1304 | STATS_INC(pool->other_pool); | 1338 | STATS_INC(pool->other_pool); |
| 1305 | for (i = 1; i < mopts.malloc_mutexes; i++) { | 1339 | for (i = 1; i < nmutexes; i++) { |
| 1306 | int j = (argpool->mutex + i) & | 1340 | u_int j = (argpool->mutex + i) & (nmutexes - 1); |
| 1307 | (mopts.malloc_mutexes - 1); | 1341 | |
| 1308 | 1342 | pool->active--; | |
| 1309 | pool->active--; | 1343 | _MALLOC_UNLOCK(pool->mutex); |
| 1310 | _MALLOC_UNLOCK(pool->mutex); | 1344 | pool = mopts.malloc_pool[j]; |
| 1311 | pool = mopts.malloc_pool[j]; | 1345 | _MALLOC_LOCK(pool->mutex); |
| 1312 | _MALLOC_LOCK(pool->mutex); | 1346 | pool->active++; |
| 1313 | pool->active++; | 1347 | r = find(pool, p); |
| 1314 | r = find(pool, p); | 1348 | if (r != NULL) { |
| 1315 | if (r != NULL) { | 1349 | *saved_function = pool->func; |
| 1316 | *saved_function = pool->func; | 1350 | pool->func = argpool->func; |
| 1317 | pool->func = argpool->func; | 1351 | break; |
| 1318 | break; | ||
| 1319 | } | ||
| 1320 | } | 1352 | } |
| 1321 | } | 1353 | } |
| 1322 | if (r == NULL) | 1354 | if (r == NULL) |
| @@ -1337,6 +1369,10 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz) | |||
| 1337 | r = findpool(p, *argpool, &pool, &saved_function); | 1369 | r = findpool(p, *argpool, &pool, &saved_function); |
| 1338 | 1370 | ||
| 1339 | REALSIZE(sz, r); | 1371 | REALSIZE(sz, r); |
| 1372 | if (pool->mmap_flag) { | ||
| 1373 | clear = 1; | ||
| 1374 | argsz = sz; | ||
| 1375 | } | ||
| 1340 | if (check) { | 1376 | if (check) { |
| 1341 | if (sz <= MALLOC_MAXCHUNK) { | 1377 | if (sz <= MALLOC_MAXCHUNK) { |
| 1342 | if (mopts.chunk_canaries && sz > 0) { | 1378 | if (mopts.chunk_canaries && sz > 0) { |
| @@ -1386,7 +1422,7 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz) | |||
| 1386 | STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); | 1422 | STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); |
| 1387 | } | 1423 | } |
| 1388 | unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0, | 1424 | unmap(pool, p, PAGEROUND(sz), clear ? argsz : 0, |
| 1389 | mopts.malloc_junk); | 1425 | pool->malloc_junk); |
| 1390 | delete(pool, r); | 1426 | delete(pool, r); |
| 1391 | } else { | 1427 | } else { |
| 1392 | /* Validate and optionally canary check */ | 1428 | /* Validate and optionally canary check */ |
| @@ -1402,7 +1438,7 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz) | |||
| 1402 | wrterror(pool, | 1438 | wrterror(pool, |
| 1403 | "double free %p", p); | 1439 | "double free %p", p); |
| 1404 | } | 1440 | } |
| 1405 | if (mopts.malloc_junk && sz > 0) | 1441 | if (pool->malloc_junk && sz > 0) |
| 1406 | memset(p, SOME_FREEJUNK, sz); | 1442 | memset(p, SOME_FREEJUNK, sz); |
| 1407 | i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; | 1443 | i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; |
| 1408 | tmp = p; | 1444 | tmp = p; |
| @@ -1410,7 +1446,7 @@ ofree(struct dir_info **argpool, void *p, int clear, int check, size_t argsz) | |||
| 1410 | if (tmp == p) | 1446 | if (tmp == p) |
| 1411 | wrterror(pool, "double free %p", tmp); | 1447 | wrterror(pool, "double free %p", tmp); |
| 1412 | pool->delayed_chunks[i] = tmp; | 1448 | pool->delayed_chunks[i] = tmp; |
| 1413 | if (mopts.malloc_junk) | 1449 | if (pool->malloc_junk) |
| 1414 | validate_junk(pool, p); | 1450 | validate_junk(pool, p); |
| 1415 | } else if (argsz > 0) | 1451 | } else if (argsz > 0) |
| 1416 | memset(p, 0, argsz); | 1452 | memset(p, 0, argsz); |
| @@ -1503,6 +1539,7 @@ orealloc(struct dir_info **argpool, void *p, size_t newsz, void *f) | |||
| 1503 | size_t oldsz, goldsz, gnewsz; | 1539 | size_t oldsz, goldsz, gnewsz; |
| 1504 | void *q, *ret; | 1540 | void *q, *ret; |
| 1505 | uint32_t chunknum; | 1541 | uint32_t chunknum; |
| 1542 | int forced; | ||
| 1506 | 1543 | ||
| 1507 | if (p == NULL) | 1544 | if (p == NULL) |
| 1508 | return omalloc(*argpool, newsz, 0, f); | 1545 | return omalloc(*argpool, newsz, 0, f); |
| @@ -1531,8 +1568,8 @@ orealloc(struct dir_info **argpool, void *p, size_t newsz, void *f) | |||
| 1531 | if (gnewsz > MALLOC_MAXCHUNK) | 1568 | if (gnewsz > MALLOC_MAXCHUNK) |
| 1532 | gnewsz += mopts.malloc_guard; | 1569 | gnewsz += mopts.malloc_guard; |
| 1533 | 1570 | ||
| 1534 | if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && | 1571 | forced = mopts.malloc_realloc || pool->mmap_flag; |
| 1535 | !mopts.malloc_realloc) { | 1572 | if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && !forced) { |
| 1536 | /* First case: from n pages sized allocation to m pages sized | 1573 | /* First case: from n pages sized allocation to m pages sized |
| 1537 | allocation, m > n */ | 1574 | allocation, m > n */ |
| 1538 | size_t roldsz = PAGEROUND(goldsz); | 1575 | size_t roldsz = PAGEROUND(goldsz); |
| @@ -1549,15 +1586,15 @@ orealloc(struct dir_info **argpool, void *p, size_t newsz, void *f) | |||
| 1549 | if (q == hint) | 1586 | if (q == hint) |
| 1550 | goto gotit; | 1587 | goto gotit; |
| 1551 | zapcacheregion(pool, hint, needed); | 1588 | zapcacheregion(pool, hint, needed); |
| 1552 | q = MQUERY(hint, needed); | 1589 | q = MQUERY(hint, needed, pool->mmap_flag); |
| 1553 | if (q == hint) | 1590 | if (q == hint) |
| 1554 | q = MMAPA(hint, needed); | 1591 | q = MMAPA(hint, needed, pool->mmap_flag); |
| 1555 | else | 1592 | else |
| 1556 | q = MAP_FAILED; | 1593 | q = MAP_FAILED; |
| 1557 | if (q == hint) { | 1594 | if (q == hint) { |
| 1558 | gotit: | 1595 | gotit: |
| 1559 | STATS_ADD(pool->malloc_used, needed); | 1596 | STATS_ADD(pool->malloc_used, needed); |
| 1560 | if (mopts.malloc_junk == 2) | 1597 | if (pool->malloc_junk == 2) |
| 1561 | memset(q, SOME_JUNK, needed); | 1598 | memset(q, SOME_JUNK, needed); |
| 1562 | r->size = gnewsz; | 1599 | r->size = gnewsz; |
| 1563 | if (r->p != p) { | 1600 | if (r->p != p) { |
| @@ -1590,7 +1627,7 @@ gotit: | |||
| 1590 | wrterror(pool, "mprotect"); | 1627 | wrterror(pool, "mprotect"); |
| 1591 | } | 1628 | } |
| 1592 | unmap(pool, (char *)r->p + rnewsz, roldsz - rnewsz, 0, | 1629 | unmap(pool, (char *)r->p + rnewsz, roldsz - rnewsz, 0, |
| 1593 | mopts.malloc_junk); | 1630 | pool->malloc_junk); |
| 1594 | r->size = gnewsz; | 1631 | r->size = gnewsz; |
| 1595 | if (MALLOC_MOVE_COND(gnewsz)) { | 1632 | if (MALLOC_MOVE_COND(gnewsz)) { |
| 1596 | void *pp = MALLOC_MOVE(r->p, gnewsz); | 1633 | void *pp = MALLOC_MOVE(r->p, gnewsz); |
| @@ -1613,7 +1650,7 @@ gotit: | |||
| 1613 | p = pp; | 1650 | p = pp; |
| 1614 | } | 1651 | } |
| 1615 | if (p == r->p) { | 1652 | if (p == r->p) { |
| 1616 | if (newsz > oldsz && mopts.malloc_junk == 2) | 1653 | if (newsz > oldsz && pool->malloc_junk == 2) |
| 1617 | memset((char *)p + newsz, SOME_JUNK, | 1654 | memset((char *)p + newsz, SOME_JUNK, |
| 1618 | rnewsz - mopts.malloc_guard - | 1655 | rnewsz - mopts.malloc_guard - |
| 1619 | newsz); | 1656 | newsz); |
| @@ -1627,9 +1664,9 @@ gotit: | |||
| 1627 | } | 1664 | } |
| 1628 | if (oldsz <= MALLOC_MAXCHUNK && oldsz > 0 && | 1665 | if (oldsz <= MALLOC_MAXCHUNK && oldsz > 0 && |
| 1629 | newsz <= MALLOC_MAXCHUNK && newsz > 0 && | 1666 | newsz <= MALLOC_MAXCHUNK && newsz > 0 && |
| 1630 | 1 << find_chunksize(newsz) == oldsz && !mopts.malloc_realloc) { | 1667 | 1 << find_chunksize(newsz) == oldsz && !forced) { |
| 1631 | /* do not reallocate if new size fits good in existing chunk */ | 1668 | /* do not reallocate if new size fits good in existing chunk */ |
| 1632 | if (mopts.malloc_junk == 2) | 1669 | if (pool->malloc_junk == 2) |
| 1633 | memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); | 1670 | memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); |
| 1634 | if (mopts.chunk_canaries) { | 1671 | if (mopts.chunk_canaries) { |
| 1635 | info->bits[info->offset + chunknum] = newsz; | 1672 | info->bits[info->offset + chunknum] = newsz; |
| @@ -1637,7 +1674,7 @@ gotit: | |||
| 1637 | } | 1674 | } |
| 1638 | STATS_SETF(r, f); | 1675 | STATS_SETF(r, f); |
| 1639 | ret = p; | 1676 | ret = p; |
| 1640 | } else if (newsz != oldsz || mopts.malloc_realloc) { | 1677 | } else if (newsz != oldsz || forced) { |
| 1641 | /* create new allocation */ | 1678 | /* create new allocation */ |
| 1642 | q = omalloc(pool, newsz, 0, f); | 1679 | q = omalloc(pool, newsz, 0, f); |
| 1643 | if (q == NULL) { | 1680 | if (q == NULL) { |
| @@ -1670,30 +1707,13 @@ realloc(void *ptr, size_t size) | |||
| 1670 | void *r; | 1707 | void *r; |
| 1671 | int saved_errno = errno; | 1708 | int saved_errno = errno; |
| 1672 | 1709 | ||
| 1673 | d = getpool(); | 1710 | PROLOGUE(getpool(), "realloc") |
| 1674 | if (d == NULL) { | ||
| 1675 | _malloc_init(0); | ||
| 1676 | d = getpool(); | ||
| 1677 | } | ||
| 1678 | _MALLOC_LOCK(d->mutex); | ||
| 1679 | d->func = "realloc"; | ||
| 1680 | if (d->active++) { | ||
| 1681 | malloc_recurse(d); | ||
| 1682 | return NULL; | ||
| 1683 | } | ||
| 1684 | r = orealloc(&d, ptr, size, CALLER); | 1711 | r = orealloc(&d, ptr, size, CALLER); |
| 1685 | 1712 | EPILOGUE() | |
| 1686 | d->active--; | ||
| 1687 | _MALLOC_UNLOCK(d->mutex); | ||
| 1688 | if (r == NULL && mopts.malloc_xmalloc) | ||
| 1689 | wrterror(d, "out of memory"); | ||
| 1690 | if (r != NULL) | ||
| 1691 | errno = saved_errno; | ||
| 1692 | return r; | 1713 | return r; |
| 1693 | } | 1714 | } |
| 1694 | /*DEF_STRONG(realloc);*/ | 1715 | /*DEF_STRONG(realloc);*/ |
| 1695 | 1716 | ||
| 1696 | |||
| 1697 | /* | 1717 | /* |
| 1698 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX | 1718 | * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX |
| 1699 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW | 1719 | * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW |
| @@ -1707,15 +1727,10 @@ calloc(size_t nmemb, size_t size) | |||
| 1707 | void *r; | 1727 | void *r; |
| 1708 | int saved_errno = errno; | 1728 | int saved_errno = errno; |
| 1709 | 1729 | ||
| 1710 | d = getpool(); | 1730 | PROLOGUE(getpool(), "calloc") |
| 1711 | if (d == NULL) { | ||
| 1712 | _malloc_init(0); | ||
| 1713 | d = getpool(); | ||
| 1714 | } | ||
| 1715 | _MALLOC_LOCK(d->mutex); | ||
| 1716 | d->func = "calloc"; | ||
| 1717 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | 1731 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && |
| 1718 | nmemb > 0 && SIZE_MAX / nmemb < size) { | 1732 | nmemb > 0 && SIZE_MAX / nmemb < size) { |
| 1733 | d->active--; | ||
| 1719 | _MALLOC_UNLOCK(d->mutex); | 1734 | _MALLOC_UNLOCK(d->mutex); |
| 1720 | if (mopts.malloc_xmalloc) | 1735 | if (mopts.malloc_xmalloc) |
| 1721 | wrterror(d, "out of memory"); | 1736 | wrterror(d, "out of memory"); |
| @@ -1723,23 +1738,37 @@ calloc(size_t nmemb, size_t size) | |||
| 1723 | return NULL; | 1738 | return NULL; |
| 1724 | } | 1739 | } |
| 1725 | 1740 | ||
| 1726 | if (d->active++) { | 1741 | size *= nmemb; |
| 1727 | malloc_recurse(d); | 1742 | r = omalloc(d, size, 1, CALLER); |
| 1743 | EPILOGUE() | ||
| 1744 | return r; | ||
| 1745 | } | ||
| 1746 | /*DEF_STRONG(calloc);*/ | ||
| 1747 | |||
| 1748 | void * | ||
| 1749 | calloc_conceal(size_t nmemb, size_t size) | ||
| 1750 | { | ||
| 1751 | struct dir_info *d; | ||
| 1752 | void *r; | ||
| 1753 | int saved_errno = errno; | ||
| 1754 | |||
| 1755 | PROLOGUE(mopts.malloc_pool[0], "calloc_conceal") | ||
| 1756 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | ||
| 1757 | nmemb > 0 && SIZE_MAX / nmemb < size) { | ||
| 1758 | d->active--; | ||
| 1759 | _MALLOC_UNLOCK(d->mutex); | ||
| 1760 | if (mopts.malloc_xmalloc) | ||
| 1761 | wrterror(d, "out of memory"); | ||
| 1762 | errno = ENOMEM; | ||
| 1728 | return NULL; | 1763 | return NULL; |
| 1729 | } | 1764 | } |
| 1730 | 1765 | ||
| 1731 | size *= nmemb; | 1766 | size *= nmemb; |
| 1732 | r = omalloc(d, size, 1, CALLER); | 1767 | r = omalloc(d, size, 1, CALLER); |
| 1733 | 1768 | EPILOGUE() | |
| 1734 | d->active--; | ||
| 1735 | _MALLOC_UNLOCK(d->mutex); | ||
| 1736 | if (r == NULL && mopts.malloc_xmalloc) | ||
| 1737 | wrterror(d, "out of memory"); | ||
| 1738 | if (r != NULL) | ||
| 1739 | errno = saved_errno; | ||
| 1740 | return r; | 1769 | return r; |
| 1741 | } | 1770 | } |
| 1742 | /*DEF_STRONG(calloc);*/ | 1771 | DEF_WEAK(calloc_conceal); |
| 1743 | 1772 | ||
| 1744 | static void * | 1773 | static void * |
| 1745 | orecallocarray(struct dir_info **argpool, void *p, size_t oldsize, | 1774 | orecallocarray(struct dir_info **argpool, void *p, size_t oldsize, |
| @@ -1858,17 +1887,11 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) | |||
| 1858 | if (!mopts.internal_funcs) | 1887 | if (!mopts.internal_funcs) |
| 1859 | return recallocarray_p(ptr, oldnmemb, newnmemb, size); | 1888 | return recallocarray_p(ptr, oldnmemb, newnmemb, size); |
| 1860 | 1889 | ||
| 1861 | d = getpool(); | 1890 | PROLOGUE(getpool(), "recallocarray") |
| 1862 | if (d == NULL) { | ||
| 1863 | _malloc_init(0); | ||
| 1864 | d = getpool(); | ||
| 1865 | } | ||
| 1866 | |||
| 1867 | _MALLOC_LOCK(d->mutex); | ||
| 1868 | d->func = "recallocarray"; | ||
| 1869 | 1891 | ||
| 1870 | if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | 1892 | if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && |
| 1871 | newnmemb > 0 && SIZE_MAX / newnmemb < size) { | 1893 | newnmemb > 0 && SIZE_MAX / newnmemb < size) { |
| 1894 | d->active--; | ||
| 1872 | _MALLOC_UNLOCK(d->mutex); | 1895 | _MALLOC_UNLOCK(d->mutex); |
| 1873 | if (mopts.malloc_xmalloc) | 1896 | if (mopts.malloc_xmalloc) |
| 1874 | wrterror(d, "out of memory"); | 1897 | wrterror(d, "out of memory"); |
| @@ -1880,6 +1903,7 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) | |||
| 1880 | if (ptr != NULL) { | 1903 | if (ptr != NULL) { |
| 1881 | if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | 1904 | if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && |
| 1882 | oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { | 1905 | oldnmemb > 0 && SIZE_MAX / oldnmemb < size) { |
| 1906 | d->active--; | ||
| 1883 | _MALLOC_UNLOCK(d->mutex); | 1907 | _MALLOC_UNLOCK(d->mutex); |
| 1884 | errno = EINVAL; | 1908 | errno = EINVAL; |
| 1885 | return NULL; | 1909 | return NULL; |
| @@ -1887,24 +1911,12 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) | |||
| 1887 | oldsize = oldnmemb * size; | 1911 | oldsize = oldnmemb * size; |
| 1888 | } | 1912 | } |
| 1889 | 1913 | ||
| 1890 | if (d->active++) { | ||
| 1891 | malloc_recurse(d); | ||
| 1892 | return NULL; | ||
| 1893 | } | ||
| 1894 | |||
| 1895 | r = orecallocarray(&d, ptr, oldsize, newsize, CALLER); | 1914 | r = orecallocarray(&d, ptr, oldsize, newsize, CALLER); |
| 1896 | 1915 | EPILOGUE() | |
| 1897 | d->active--; | ||
| 1898 | _MALLOC_UNLOCK(d->mutex); | ||
| 1899 | if (r == NULL && mopts.malloc_xmalloc) | ||
| 1900 | wrterror(d, "out of memory"); | ||
| 1901 | if (r != NULL) | ||
| 1902 | errno = saved_errno; | ||
| 1903 | return r; | 1916 | return r; |
| 1904 | } | 1917 | } |
| 1905 | DEF_WEAK(recallocarray); | 1918 | DEF_WEAK(recallocarray); |
| 1906 | 1919 | ||
| 1907 | |||
| 1908 | static void * | 1920 | static void * |
| 1909 | mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) | 1921 | mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) |
| 1910 | { | 1922 | { |
| @@ -1987,7 +1999,7 @@ omemalign(struct dir_info *pool, size_t alignment, size_t sz, int zero_fill, | |||
| 1987 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); | 1999 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); |
| 1988 | } | 2000 | } |
| 1989 | 2001 | ||
| 1990 | if (mopts.malloc_junk == 2) { | 2002 | if (pool->malloc_junk == 2) { |
| 1991 | if (zero_fill) | 2003 | if (zero_fill) |
| 1992 | memset((char *)p + sz - mopts.malloc_guard, | 2004 | memset((char *)p + sz - mopts.malloc_guard, |
| 1993 | SOME_JUNK, psz - sz); | 2005 | SOME_JUNK, psz - sz); |
| @@ -2059,26 +2071,9 @@ aligned_alloc(size_t alignment, size_t size) | |||
| 2059 | return NULL; | 2071 | return NULL; |
| 2060 | } | 2072 | } |
| 2061 | 2073 | ||
| 2062 | d = getpool(); | 2074 | PROLOGUE(getpool(), "aligned_alloc") |
| 2063 | if (d == NULL) { | ||
| 2064 | _malloc_init(0); | ||
| 2065 | d = getpool(); | ||
| 2066 | } | ||
| 2067 | _MALLOC_LOCK(d->mutex); | ||
| 2068 | d->func = "aligned_alloc"; | ||
| 2069 | if (d->active++) { | ||
| 2070 | malloc_recurse(d); | ||
| 2071 | return NULL; | ||
| 2072 | } | ||
| 2073 | r = omemalign(d, alignment, size, 0, CALLER); | 2075 | r = omemalign(d, alignment, size, 0, CALLER); |
| 2074 | d->active--; | 2076 | EPILOGUE() |
| 2075 | _MALLOC_UNLOCK(d->mutex); | ||
| 2076 | if (r == NULL) { | ||
| 2077 | if (mopts.malloc_xmalloc) | ||
| 2078 | wrterror(d, "out of memory"); | ||
| 2079 | return NULL; | ||
| 2080 | } | ||
| 2081 | errno = saved_errno; | ||
| 2082 | return r; | 2077 | return r; |
| 2083 | } | 2078 | } |
| 2084 | /*DEF_STRONG(aligned_alloc);*/ | 2079 | /*DEF_STRONG(aligned_alloc);*/ |
| @@ -2121,7 +2116,7 @@ putleakinfo(void *f, size_t sz, int cnt) | |||
| 2121 | if (p == NULL) { | 2116 | if (p == NULL) { |
| 2122 | if (page == NULL || | 2117 | if (page == NULL || |
| 2123 | used >= MALLOC_PAGESIZE / sizeof(struct leaknode)) { | 2118 | used >= MALLOC_PAGESIZE / sizeof(struct leaknode)) { |
| 2124 | page = MMAP(MALLOC_PAGESIZE); | 2119 | page = MMAP(MALLOC_PAGESIZE, 0); |
| 2125 | if (page == MAP_FAILED) | 2120 | if (page == MAP_FAILED) |
| 2126 | return; | 2121 | return; |
| 2127 | used = 0; | 2122 | used = 0; |
| @@ -2149,7 +2144,7 @@ dump_leaks(int fd) | |||
| 2149 | dprintf(fd, " f sum # avg\n"); | 2144 | dprintf(fd, " f sum # avg\n"); |
| 2150 | /* XXX only one page of summary */ | 2145 | /* XXX only one page of summary */ |
| 2151 | if (malloc_leaks == NULL) | 2146 | if (malloc_leaks == NULL) |
| 2152 | malloc_leaks = MMAP(MALLOC_PAGESIZE); | 2147 | malloc_leaks = MMAP(MALLOC_PAGESIZE, 0); |
| 2153 | if (malloc_leaks != MAP_FAILED) | 2148 | if (malloc_leaks != MAP_FAILED) |
| 2154 | memset(malloc_leaks, 0, MALLOC_PAGESIZE); | 2149 | memset(malloc_leaks, 0, MALLOC_PAGESIZE); |
| 2155 | RBT_FOREACH(p, leaktree, &leakhead) { | 2150 | RBT_FOREACH(p, leaktree, &leakhead) { |
| @@ -2219,7 +2214,7 @@ dump_free_page_info(int fd, struct dir_info *d) | |||
| 2219 | int i; | 2214 | int i; |
| 2220 | 2215 | ||
| 2221 | dprintf(fd, "Free pages cached: %zu\n", d->free_regions_size); | 2216 | dprintf(fd, "Free pages cached: %zu\n", d->free_regions_size); |
| 2222 | for (i = 0; i < mopts.malloc_cache; i++) { | 2217 | for (i = 0; i < d->malloc_cache; i++) { |
| 2223 | if (d->free_regions[i].p != NULL) { | 2218 | if (d->free_regions[i].p != NULL) { |
| 2224 | dprintf(fd, "%2d) ", i); | 2219 | dprintf(fd, "%2d) ", i); |
| 2225 | dprintf(fd, "free at %p: %zu\n", | 2220 | dprintf(fd, "free at %p: %zu\n", |
| @@ -2236,6 +2231,8 @@ malloc_dump1(int fd, int poolno, struct dir_info *d) | |||
| 2236 | dprintf(fd, "Malloc dir of %s pool %d at %p\n", __progname, poolno, d); | 2231 | dprintf(fd, "Malloc dir of %s pool %d at %p\n", __progname, poolno, d); |
| 2237 | if (d == NULL) | 2232 | if (d == NULL) |
| 2238 | return; | 2233 | return; |
| 2234 | dprintf(fd, "J=%d cache=%u Fl=%x\n", | ||
| 2235 | d->malloc_junk, d->malloc_cache, d->mmap_flag); | ||
| 2239 | dprintf(fd, "Region slots free %zu/%zu\n", | 2236 | dprintf(fd, "Region slots free %zu/%zu\n", |
| 2240 | d->regions_free, d->regions_total); | 2237 | d->regions_free, d->regions_total); |
| 2241 | dprintf(fd, "Finds %zu/%zu\n", d->finds, d->find_collisions); | 2238 | dprintf(fd, "Finds %zu/%zu\n", d->finds, d->find_collisions); |
| @@ -2323,11 +2320,11 @@ malloc_exit(void) | |||
| 2323 | dprintf(fd, "******** Start dump %s *******\n", __progname); | 2320 | dprintf(fd, "******** Start dump %s *******\n", __progname); |
| 2324 | dprintf(fd, | 2321 | dprintf(fd, |
| 2325 | "MT=%d M=%u I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", | 2322 | "MT=%d M=%u I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", |
| 2326 | mopts.malloc_mt, mopts.mallloc_mutexes, | 2323 | mopts.malloc_mt, mopts.malloc_mutexes, |
| 2327 | mopts.internal_funcs, mopts.malloc_freecheck, | 2324 | mopts.internal_funcs, mopts.malloc_freecheck, |
| 2328 | mopts.malloc_freeunmap, mopts.malloc_junk, | 2325 | mopts.malloc_freeunmap, mopts.def_malloc_junk, |
| 2329 | mopts.malloc_realloc, mopts.malloc_xmalloc, | 2326 | mopts.malloc_realloc, mopts.malloc_xmalloc, |
| 2330 | mopts.chunk_canaries, mopts.malloc_cache, | 2327 | mopts.chunk_canaries, mopts.def_malloc_cache, |
| 2331 | mopts.malloc_guard); | 2328 | mopts.malloc_guard); |
| 2332 | 2329 | ||
| 2333 | for (i = 0; i < mopts.malloc_mutexes; i++) | 2330 | for (i = 0; i < mopts.malloc_mutexes; i++) |
