diff options
Diffstat (limited to 'src/lib/libc')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 186 |
1 files changed, 125 insertions, 61 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 028eff2b2d..ace34c96f6 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.83 2006/05/14 19:53:40 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.84 2006/10/24 04:35:30 tedu Exp $ */ |
| 2 | 2 | ||
| 3 | /* | 3 | /* |
| 4 | * ---------------------------------------------------------------------------- | 4 | * ---------------------------------------------------------------------------- |
| @@ -75,6 +75,18 @@ | |||
| 75 | #define malloc_pageshift (PGSHIFT) | 75 | #define malloc_pageshift (PGSHIFT) |
| 76 | #endif | 76 | #endif |
| 77 | 77 | ||
| 78 | #ifndef malloc_minsize | ||
| 79 | #define malloc_minsize 16UL | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #if !defined(malloc_pagesize) | ||
| 83 | #define malloc_pagesize (1UL<<malloc_pageshift) | ||
| 84 | #endif | ||
| 85 | |||
| 86 | /* How many bits per u_long in the bitmap */ | ||
| 87 | #define MALLOC_BITS (NBBY * sizeof(u_long)) | ||
| 88 | |||
| 89 | |||
| 78 | /* | 90 | /* |
| 79 | * No user serviceable parts behind this point. | 91 | * No user serviceable parts behind this point. |
| 80 | * | 92 | * |
| @@ -87,12 +99,9 @@ struct pginfo { | |||
| 87 | u_short shift; /* How far to shift for this size chunks */ | 99 | u_short shift; /* How far to shift for this size chunks */ |
| 88 | u_short free; /* How many free chunks */ | 100 | u_short free; /* How many free chunks */ |
| 89 | u_short total; /* How many chunk */ | 101 | u_short total; /* How many chunk */ |
| 90 | u_long bits[1];/* Which chunks are free */ | 102 | u_long bits[(malloc_pagesize / malloc_minsize) / MALLOC_BITS];/* Which chunks are free */ |
| 91 | }; | 103 | }; |
| 92 | 104 | ||
| 93 | /* How many bits per u_long in the bitmap */ | ||
| 94 | #define MALLOC_BITS (NBBY * sizeof(u_long)) | ||
| 95 | |||
| 96 | /* | 105 | /* |
| 97 | * This structure describes a number of free pages. | 106 | * This structure describes a number of free pages. |
| 98 | */ | 107 | */ |
| @@ -113,14 +122,6 @@ struct pgfree { | |||
| 113 | #define MALLOC_FOLLOW ((struct pginfo*) 3) | 122 | #define MALLOC_FOLLOW ((struct pginfo*) 3) |
| 114 | #define MALLOC_MAGIC ((struct pginfo*) 4) | 123 | #define MALLOC_MAGIC ((struct pginfo*) 4) |
| 115 | 124 | ||
| 116 | #ifndef malloc_minsize | ||
| 117 | #define malloc_minsize 16UL | ||
| 118 | #endif | ||
| 119 | |||
| 120 | #if !defined(malloc_pagesize) | ||
| 121 | #define malloc_pagesize (1UL<<malloc_pageshift) | ||
| 122 | #endif | ||
| 123 | |||
| 124 | #if ((1UL<<malloc_pageshift) != malloc_pagesize) | 125 | #if ((1UL<<malloc_pageshift) != malloc_pagesize) |
| 125 | #error "(1UL<<malloc_pageshift) != malloc_pagesize" | 126 | #error "(1UL<<malloc_pageshift) != malloc_pagesize" |
| 126 | #endif | 127 | #endif |
| @@ -254,6 +255,66 @@ static void ifree(void *ptr); | |||
| 254 | static void *irealloc(void *ptr, size_t size); | 255 | static void *irealloc(void *ptr, size_t size); |
| 255 | static void *malloc_bytes(size_t size); | 256 | static void *malloc_bytes(size_t size); |
| 256 | 257 | ||
| 258 | static struct pginfo *pginfo_list; | ||
| 259 | |||
| 260 | static struct pgfree *pgfree_list; | ||
| 261 | |||
| 262 | static struct pgfree * | ||
| 263 | alloc_pgfree() | ||
| 264 | { | ||
| 265 | struct pgfree *p; | ||
| 266 | int i; | ||
| 267 | |||
| 268 | if (pgfree_list == NULL) { | ||
| 269 | p = MMAP(malloc_pagesize); | ||
| 270 | if (!p) | ||
| 271 | return NULL; | ||
| 272 | for (i = 0; i < malloc_pagesize / sizeof(*p); i++) { | ||
| 273 | p[i].next = pgfree_list; | ||
| 274 | pgfree_list = &p[i]; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | p = pgfree_list; | ||
| 278 | pgfree_list = p->next; | ||
| 279 | memset(p, 0, sizeof *p); | ||
| 280 | return p; | ||
| 281 | } | ||
| 282 | |||
| 283 | static struct pginfo * | ||
| 284 | alloc_pginfo() | ||
| 285 | { | ||
| 286 | struct pginfo *p; | ||
| 287 | int i; | ||
| 288 | |||
| 289 | if (pginfo_list == NULL) { | ||
| 290 | p = MMAP(malloc_pagesize); | ||
| 291 | if (!p) | ||
| 292 | return NULL; | ||
| 293 | for (i = 0; i < malloc_pagesize / sizeof(*p); i++) { | ||
| 294 | p[i].next = pginfo_list; | ||
| 295 | pginfo_list = &p[i]; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | p = pginfo_list; | ||
| 299 | pginfo_list = p->next; | ||
| 300 | memset(p, 0, sizeof *p); | ||
| 301 | return p; | ||
| 302 | } | ||
| 303 | |||
| 304 | static void | ||
| 305 | put_pgfree(struct pgfree *p) | ||
| 306 | { | ||
| 307 | p->next = pgfree_list; | ||
| 308 | pgfree_list = p; | ||
| 309 | } | ||
| 310 | |||
| 311 | static void | ||
| 312 | put_pginfo(struct pginfo *p) | ||
| 313 | { | ||
| 314 | p->next = pginfo_list; | ||
| 315 | pginfo_list = p; | ||
| 316 | } | ||
| 317 | |||
| 257 | /* | 318 | /* |
| 258 | * Function for page directory lookup. | 319 | * Function for page directory lookup. |
| 259 | */ | 320 | */ |
| @@ -764,12 +825,12 @@ malloc_init(void) | |||
| 764 | static void * | 825 | static void * |
| 765 | malloc_pages(size_t size) | 826 | malloc_pages(size_t size) |
| 766 | { | 827 | { |
| 767 | void *p, *delay_free = NULL, *tp; | 828 | void *p, *tp; |
| 768 | int i; | 829 | int i; |
| 769 | struct pginfo **pd; | 830 | struct pginfo **pd; |
| 770 | struct pdinfo *pi; | 831 | struct pdinfo *pi; |
| 771 | u_long pidx, index; | 832 | u_long pidx, index; |
| 772 | struct pgfree *pf; | 833 | struct pgfree *pf, *delay_free = NULL; |
| 773 | 834 | ||
| 774 | size = pageround(size) + malloc_guard; | 835 | size = pageround(size) + malloc_guard; |
| 775 | 836 | ||
| @@ -936,7 +997,7 @@ malloc_pages(size_t size) | |||
| 936 | if (px == NULL) | 997 | if (px == NULL) |
| 937 | px = delay_free; | 998 | px = delay_free; |
| 938 | else | 999 | else |
| 939 | ifree(delay_free); | 1000 | put_pgfree(delay_free); |
| 940 | } | 1001 | } |
| 941 | return (p); | 1002 | return (p); |
| 942 | } | 1003 | } |
| @@ -945,7 +1006,7 @@ malloc_pages(size_t size) | |||
| 945 | * Allocate a page of fragments | 1006 | * Allocate a page of fragments |
| 946 | */ | 1007 | */ |
| 947 | 1008 | ||
| 948 | static __inline__ int | 1009 | static int |
| 949 | malloc_make_chunks(int bits) | 1010 | malloc_make_chunks(int bits) |
| 950 | { | 1011 | { |
| 951 | struct pginfo *bp, **pd; | 1012 | struct pginfo *bp, **pd; |
| @@ -955,17 +1016,13 @@ malloc_make_chunks(int bits) | |||
| 955 | #endif /* MALLOC_EXTRA_SANITY */ | 1016 | #endif /* MALLOC_EXTRA_SANITY */ |
| 956 | void *pp; | 1017 | void *pp; |
| 957 | long i, k; | 1018 | long i, k; |
| 958 | size_t l; | ||
| 959 | 1019 | ||
| 960 | /* Allocate a new bucket */ | 1020 | /* Allocate a new bucket */ |
| 961 | pp = malloc_pages((size_t) malloc_pagesize); | 1021 | pp = malloc_pages((size_t)malloc_pagesize); |
| 962 | if (pp == NULL) | 1022 | if (pp == NULL) |
| 963 | return (0); | 1023 | return (0); |
| 964 | 1024 | ||
| 965 | /* Find length of admin structure */ | 1025 | /* Find length of admin structure */ |
| 966 | l = sizeof *bp - sizeof(u_long); | ||
| 967 | l += sizeof(u_long) * | ||
| 968 | (((malloc_pagesize >> bits) + MALLOC_BITS - 1) / MALLOC_BITS); | ||
| 969 | 1026 | ||
| 970 | /* Don't waste more than two chunks on this */ | 1027 | /* Don't waste more than two chunks on this */ |
| 971 | 1028 | ||
| @@ -975,14 +1032,10 @@ malloc_make_chunks(int bits) | |||
| 975 | * pginfo page. | 1032 | * pginfo page. |
| 976 | * --> Treat it like the big chunk alloc, get a second data page. | 1033 | * --> Treat it like the big chunk alloc, get a second data page. |
| 977 | */ | 1034 | */ |
| 978 | if (bits != 0 && (1UL << (bits)) <= l + l) { | 1035 | bp = alloc_pginfo(); |
| 979 | bp = (struct pginfo *) pp; | 1036 | if (bp == NULL) { |
| 980 | } else { | 1037 | ifree(pp); |
| 981 | bp = (struct pginfo *) imalloc(l); | 1038 | return (0); |
| 982 | if (bp == NULL) { | ||
| 983 | ifree(pp); | ||
| 984 | return (0); | ||
| 985 | } | ||
| 986 | } | 1039 | } |
| 987 | 1040 | ||
| 988 | /* memory protect the page allocated in the malloc(0) case */ | 1041 | /* memory protect the page allocated in the malloc(0) case */ |
| @@ -998,7 +1051,7 @@ malloc_make_chunks(int bits) | |||
| 998 | k = mprotect(pp, malloc_pagesize, PROT_NONE); | 1051 | k = mprotect(pp, malloc_pagesize, PROT_NONE); |
| 999 | if (k < 0) { | 1052 | if (k < 0) { |
| 1000 | ifree(pp); | 1053 | ifree(pp); |
| 1001 | ifree(bp); | 1054 | put_pginfo(bp); |
| 1002 | return (0); | 1055 | return (0); |
| 1003 | } | 1056 | } |
| 1004 | } else { | 1057 | } else { |
| @@ -1019,18 +1072,6 @@ malloc_make_chunks(int bits) | |||
| 1019 | for (; i < k; i++) | 1072 | for (; i < k; i++) |
| 1020 | bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS); | 1073 | bp->bits[i / MALLOC_BITS] |= 1UL << (i % MALLOC_BITS); |
| 1021 | 1074 | ||
| 1022 | k = (long)l; | ||
| 1023 | if (bp == bp->page) { | ||
| 1024 | /* Mark the ones we stole for ourselves */ | ||
| 1025 | for (i = 0; k > 0; i++) { | ||
| 1026 | bp->bits[i / MALLOC_BITS] &= ~(1UL << (i % MALLOC_BITS)); | ||
| 1027 | bp->free--; | ||
| 1028 | bp->total--; | ||
| 1029 | k -= (1 << bits); | ||
| 1030 | } | ||
| 1031 | } | ||
| 1032 | /* MALLOC_LOCK */ | ||
| 1033 | |||
| 1034 | pdir_lookup(ptr2index(pp), &pi); | 1075 | pdir_lookup(ptr2index(pp), &pi); |
| 1035 | #ifdef MALLOC_EXTRA_SANITY | 1076 | #ifdef MALLOC_EXTRA_SANITY |
| 1036 | pidx = PI_IDX(ptr2index(pp)); | 1077 | pidx = PI_IDX(ptr2index(pp)); |
| @@ -1325,7 +1366,7 @@ irealloc(void *ptr, size_t size) | |||
| 1325 | /* | 1366 | /* |
| 1326 | * Free a sequence of pages | 1367 | * Free a sequence of pages |
| 1327 | */ | 1368 | */ |
| 1328 | static __inline__ void | 1369 | static void |
| 1329 | free_pages(void *ptr, u_long index, struct pginfo * info) | 1370 | free_pages(void *ptr, u_long index, struct pginfo * info) |
| 1330 | { | 1371 | { |
| 1331 | u_long i, pidx, lidx; | 1372 | u_long i, pidx, lidx; |
| @@ -1409,8 +1450,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info) | |||
| 1409 | mprotect(ptr, l, PROT_NONE); | 1450 | mprotect(ptr, l, PROT_NONE); |
| 1410 | 1451 | ||
| 1411 | /* Add to free-list. */ | 1452 | /* Add to free-list. */ |
| 1412 | if (px == NULL && (px = malloc_bytes(sizeof *px)) == NULL) | 1453 | if (px == NULL && (px = alloc_pgfree()) == NULL) |
| 1413 | goto not_return; | 1454 | goto not_return; |
| 1414 | px->page = ptr; | 1455 | px->page = ptr; |
| 1415 | px->pdir = spi; | 1456 | px->pdir = spi; |
| 1416 | px->size = l; | 1457 | px->size = l; |
| @@ -1578,7 +1619,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) | |||
| 1578 | /* XXX: We could realloc/shrink the pagedir here I guess. */ | 1619 | /* XXX: We could realloc/shrink the pagedir here I guess. */ |
| 1579 | if (pf->size == 0) { /* Remove from free-list as well. */ | 1620 | if (pf->size == 0) { /* Remove from free-list as well. */ |
| 1580 | if (px) | 1621 | if (px) |
| 1581 | ifree(px); | 1622 | put_pgfree(px); |
| 1582 | if ((px = pf->prev) != &free_list) { | 1623 | if ((px = pf->prev) != &free_list) { |
| 1583 | if (pi == NULL && last_index == (index - 1)) { | 1624 | if (pi == NULL && last_index == (index - 1)) { |
| 1584 | if (spi == NULL) { | 1625 | if (spi == NULL) { |
| @@ -1592,7 +1633,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) | |||
| 1592 | pdi_mod) - 1; | 1633 | pdi_mod) - 1; |
| 1593 | for (pi = spi, i = index; | 1634 | for (pi = spi, i = index; |
| 1594 | pd[PI_OFF(i)] == MALLOC_NOT_MINE; | 1635 | pd[PI_OFF(i)] == MALLOC_NOT_MINE; |
| 1595 | i--) | 1636 | i--) { |
| 1596 | #ifdef MALLOC_EXTRA_SANITY | 1637 | #ifdef MALLOC_EXTRA_SANITY |
| 1597 | if (!PI_OFF(i)) { | 1638 | if (!PI_OFF(i)) { |
| 1598 | pi = pi->prev; | 1639 | pi = pi->prev; |
| @@ -1601,10 +1642,8 @@ free_pages(void *ptr, u_long index, struct pginfo * info) | |||
| 1601 | pd = pi->base; | 1642 | pd = pi->base; |
| 1602 | i = (PD_IDX(pi->dirnum) + 1) * pdi_mod; | 1643 | i = (PD_IDX(pi->dirnum) + 1) * pdi_mod; |
| 1603 | } | 1644 | } |
| 1604 | #else /* !MALLOC_EXTRA_SANITY */ | ||
| 1605 | { | ||
| 1606 | } | ||
| 1607 | #endif /* MALLOC_EXTRA_SANITY */ | 1645 | #endif /* MALLOC_EXTRA_SANITY */ |
| 1646 | } | ||
| 1608 | malloc_brk = index2ptr(i + 1); | 1647 | malloc_brk = index2ptr(i + 1); |
| 1609 | } | 1648 | } |
| 1610 | last_index = i; | 1649 | last_index = i; |
| @@ -1622,7 +1661,7 @@ free_pages(void *ptr, u_long index, struct pginfo * info) | |||
| 1622 | } | 1661 | } |
| 1623 | not_return: | 1662 | not_return: |
| 1624 | if (pt != NULL) | 1663 | if (pt != NULL) |
| 1625 | ifree(pt); | 1664 | put_pgfree(pt); |
| 1626 | } | 1665 | } |
| 1627 | 1666 | ||
| 1628 | /* | 1667 | /* |
| @@ -1630,16 +1669,41 @@ not_return: | |||
| 1630 | */ | 1669 | */ |
| 1631 | 1670 | ||
| 1632 | /* ARGSUSED */ | 1671 | /* ARGSUSED */ |
| 1633 | static __inline__ void | 1672 | static void |
| 1634 | free_bytes(void *ptr, u_long index, struct pginfo * info) | 1673 | free_bytes(void *ptr) |
| 1635 | { | 1674 | { |
| 1636 | struct pginfo **mp, **pd; | 1675 | struct pginfo **mp, **pd, *info; |
| 1637 | struct pdinfo *pi; | 1676 | struct pdinfo *pi; |
| 1638 | #ifdef MALLOC_EXTRA_SANITY | 1677 | #ifdef MALLOC_EXTRA_SANITY |
| 1639 | u_long pidx; | 1678 | u_long pidx; |
| 1640 | #endif /* MALLOC_EXTRA_SANITY */ | 1679 | #endif /* MALLOC_EXTRA_SANITY */ |
| 1680 | u_long index; | ||
| 1641 | void *vp; | 1681 | void *vp; |
| 1642 | long i; | 1682 | long i; |
| 1683 | void *tmpptr; | ||
| 1684 | unsigned int tmpidx; | ||
| 1685 | /* pointers that we will want to free at some future time */ | ||
| 1686 | static void *chunk_buffer[16]; | ||
| 1687 | |||
| 1688 | |||
| 1689 | /* delay return, returning a random something from before instead */ | ||
| 1690 | tmpidx = arc4random() % 16; | ||
| 1691 | tmpptr = chunk_buffer[tmpidx]; | ||
| 1692 | chunk_buffer[tmpidx] = ptr; | ||
| 1693 | ptr = tmpptr; | ||
| 1694 | if (!ptr) | ||
| 1695 | return; | ||
| 1696 | |||
| 1697 | index = ptr2index(ptr); | ||
| 1698 | |||
| 1699 | pdir_lookup(index, &pi); | ||
| 1700 | if (pi != last_dir) { | ||
| 1701 | prev_dir = last_dir; | ||
| 1702 | last_dir = pi; | ||
| 1703 | } | ||
| 1704 | pd = pi->base; | ||
| 1705 | info = pd[PI_OFF(index)]; | ||
| 1706 | |||
| 1643 | 1707 | ||
| 1644 | /* Find the chunk number on the page */ | 1708 | /* Find the chunk number on the page */ |
| 1645 | i = ((u_long) ptr & malloc_pagemask) >> info->shift; | 1709 | i = ((u_long) ptr & malloc_pagemask) >> info->shift; |
| @@ -1711,9 +1775,8 @@ free_bytes(void *ptr, u_long index, struct pginfo * info) | |||
| 1711 | if (info->size == 0) | 1775 | if (info->size == 0) |
| 1712 | mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE); | 1776 | mprotect(info->page, malloc_pagesize, PROT_READ | PROT_WRITE); |
| 1713 | 1777 | ||
| 1714 | vp = info->page; /* Order is important ! */ | 1778 | vp = info->page; |
| 1715 | if (vp != (void *) info) | 1779 | put_pginfo(info); |
| 1716 | ifree(info); | ||
| 1717 | ifree(vp); | 1780 | ifree(vp); |
| 1718 | } | 1781 | } |
| 1719 | 1782 | ||
| @@ -1736,7 +1799,7 @@ ifree(void *ptr) | |||
| 1736 | return; | 1799 | return; |
| 1737 | 1800 | ||
| 1738 | if (malloc_ptrguard && PTR_ALIGNED(ptr)) | 1801 | if (malloc_ptrguard && PTR_ALIGNED(ptr)) |
| 1739 | ptr = (char *) ptr - PTR_GAP; | 1802 | ptr = (char *)ptr - PTR_GAP; |
| 1740 | 1803 | ||
| 1741 | index = ptr2index(ptr); | 1804 | index = ptr2index(ptr); |
| 1742 | 1805 | ||
| @@ -1750,6 +1813,7 @@ ifree(void *ptr) | |||
| 1750 | wrtwarning("ifree: junk pointer, too high to make sense"); | 1813 | wrtwarning("ifree: junk pointer, too high to make sense"); |
| 1751 | return; | 1814 | return; |
| 1752 | } | 1815 | } |
| 1816 | |||
| 1753 | pdir_lookup(index, &pi); | 1817 | pdir_lookup(index, &pi); |
| 1754 | #ifdef MALLOC_EXTRA_SANITY | 1818 | #ifdef MALLOC_EXTRA_SANITY |
| 1755 | pidx = PI_IDX(index); | 1819 | pidx = PI_IDX(index); |
| @@ -1769,11 +1833,11 @@ ifree(void *ptr) | |||
| 1769 | if (info < MALLOC_MAGIC) | 1833 | if (info < MALLOC_MAGIC) |
| 1770 | free_pages(ptr, index, info); | 1834 | free_pages(ptr, index, info); |
| 1771 | else | 1835 | else |
| 1772 | free_bytes(ptr, index, info); | 1836 | free_bytes(ptr); |
| 1773 | 1837 | ||
| 1774 | /* does not matter if malloc_bytes fails */ | 1838 | /* does not matter if malloc_bytes fails */ |
| 1775 | if (px == NULL) | 1839 | if (px == NULL) |
| 1776 | px = malloc_bytes(sizeof *px); | 1840 | px = alloc_pgfree(); |
| 1777 | 1841 | ||
| 1778 | return; | 1842 | return; |
| 1779 | } | 1843 | } |
