summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libc/stdlib/Makefile.inc3
-rw-r--r--src/lib/libc/stdlib/malloc.c223
2 files changed, 207 insertions, 19 deletions
diff --git a/src/lib/libc/stdlib/Makefile.inc b/src/lib/libc/stdlib/Makefile.inc
index 36b5869adb..e754e09196 100644
--- a/src/lib/libc/stdlib/Makefile.inc
+++ b/src/lib/libc/stdlib/Makefile.inc
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile.inc,v 1.62 2017/03/06 18:44:21 otto Exp $ 1# $OpenBSD: Makefile.inc,v 1.63 2017/03/24 16:15:31 otto Exp $
2 2
3# stdlib sources 3# stdlib sources
4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_CPU}/stdlib ${LIBCSRCDIR}/stdlib 4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_CPU}/stdlib ${LIBCSRCDIR}/stdlib
@@ -7,7 +7,6 @@ SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \
7 exit.c ecvt.c gcvt.c getenv.c getopt_long.c \ 7 exit.c ecvt.c gcvt.c getenv.c getopt_long.c \
8 getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c insque.c \ 8 getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c insque.c \
9 l64a.c llabs.c lldiv.c lsearch.c malloc.c reallocarray.c \ 9 l64a.c llabs.c lldiv.c lsearch.c malloc.c reallocarray.c \
10 recallocarray.c \
11 merge.c posix_pty.c qsort.c radixsort.c rand.c random.c \ 10 merge.c posix_pty.c qsort.c radixsort.c rand.c random.c \
12 realpath.c remque.c setenv.c strtoimax.c \ 11 realpath.c remque.c setenv.c strtoimax.c \
13 strtol.c strtoll.c strtonum.c strtoul.c strtoull.c strtoumax.c \ 12 strtol.c strtoll.c strtonum.c strtoul.c strtoull.c strtoumax.c \
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index 0b071e6743..c67607e8fe 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.215 2017/02/15 12:31:57 jsg Exp $ */ 1/* $OpenBSD: malloc.c,v 1.216 2017/03/24 16:15:31 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>
@@ -185,6 +185,7 @@ struct malloc_readonly {
185 int malloc_realloc; /* always realloc? */ 185 int malloc_realloc; /* always realloc? */
186 int malloc_xmalloc; /* xmalloc behaviour? */ 186 int malloc_xmalloc; /* xmalloc behaviour? */
187 int chunk_canaries; /* use canaries after chunks? */ 187 int chunk_canaries; /* use canaries after chunks? */
188 int internal_recallocarray; /* use better recallocarray? */
188 u_int malloc_cache; /* free pages we cache */ 189 u_int malloc_cache; /* free pages we cache */
189 size_t malloc_guard; /* use guard pages after allocations? */ 190 size_t malloc_guard; /* use guard pages after allocations? */
190#ifdef MALLOC_STATS 191#ifdef MALLOC_STATS
@@ -330,7 +331,7 @@ getrbyte(struct dir_info *d)
330 * cache are in MALLOC_PAGESIZE units. 331 * cache are in MALLOC_PAGESIZE units.
331 */ 332 */
332static void 333static void
333unmap(struct dir_info *d, void *p, size_t sz) 334unmap(struct dir_info *d, void *p, size_t sz, int clear)
334{ 335{
335 size_t psz = sz >> MALLOC_PAGESHIFT; 336 size_t psz = sz >> MALLOC_PAGESHIFT;
336 size_t rsz, tounmap; 337 size_t rsz, tounmap;
@@ -373,6 +374,8 @@ unmap(struct dir_info *d, void *p, size_t sz)
373 for (i = 0; i < mopts.malloc_cache; i++) { 374 for (i = 0; i < mopts.malloc_cache; i++) {
374 r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)]; 375 r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)];
375 if (r->p == NULL) { 376 if (r->p == NULL) {
377 if (clear)
378 memset(p, 0, sz - mopts.malloc_guard);
376 if (mopts.malloc_junk && !mopts.malloc_freeunmap) { 379 if (mopts.malloc_junk && !mopts.malloc_freeunmap) {
377 size_t amt = mopts.malloc_junk == 1 ? 380 size_t amt = mopts.malloc_junk == 1 ?
378 MALLOC_MAXCHUNK : sz; 381 MALLOC_MAXCHUNK : sz;
@@ -863,7 +866,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum)
863 866
864 bp = alloc_chunk_info(d, bits); 867 bp = alloc_chunk_info(d, bits);
865 if (bp == NULL) { 868 if (bp == NULL) {
866 unmap(d, pp, MALLOC_PAGESIZE); 869 unmap(d, pp, MALLOC_PAGESIZE, 0);
867 return NULL; 870 return NULL;
868 } 871 }
869 872
@@ -879,7 +882,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum)
879 882
880 k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE); 883 k = mprotect(pp, MALLOC_PAGESIZE, PROT_NONE);
881 if (k < 0) { 884 if (k < 0) {
882 unmap(d, pp, MALLOC_PAGESIZE); 885 unmap(d, pp, MALLOC_PAGESIZE, 0);
883 LIST_INSERT_HEAD(&d->chunk_info_list[0], bp, entries); 886 LIST_INSERT_HEAD(&d->chunk_info_list[0], bp, entries);
884 return NULL; 887 return NULL;
885 } 888 }
@@ -1106,7 +1109,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr)
1106 1109
1107 if (info->size == 0 && !mopts.malloc_freeunmap) 1110 if (info->size == 0 && !mopts.malloc_freeunmap)
1108 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE); 1111 mprotect(info->page, MALLOC_PAGESIZE, PROT_READ | PROT_WRITE);
1109 unmap(d, info->page, MALLOC_PAGESIZE); 1112 unmap(d, info->page, MALLOC_PAGESIZE, 0);
1110 1113
1111 delete(d, r); 1114 delete(d, r);
1112 if (info->size != 0) 1115 if (info->size != 0)
@@ -1137,7 +1140,7 @@ omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f)
1137 return NULL; 1140 return NULL;
1138 } 1141 }
1139 if (insert(pool, p, sz, f)) { 1142 if (insert(pool, p, sz, f)) {
1140 unmap(pool, p, psz); 1143 unmap(pool, p, psz, 0);
1141 errno = ENOMEM; 1144 errno = ENOMEM;
1142 return NULL; 1145 return NULL;
1143 } 1146 }
@@ -1228,6 +1231,8 @@ _malloc_init(int from_rthreads)
1228 1231
1229 if (from_rthreads) 1232 if (from_rthreads)
1230 mopts.malloc_mt = 1; 1233 mopts.malloc_mt = 1;
1234 else
1235 mopts.internal_recallocarray = 1;
1231 1236
1232 /* 1237 /*
1233 * Options have been set and will never be reset. 1238 * Options have been set and will never be reset.
@@ -1290,7 +1295,7 @@ validate_junk(struct dir_info *pool, void *p)
1290} 1295}
1291 1296
1292static void 1297static void
1293ofree(struct dir_info *argpool, void *p) 1298ofree(struct dir_info *argpool, void *p, int clear)
1294{ 1299{
1295 struct dir_info *pool; 1300 struct dir_info *pool;
1296 struct region_info *r; 1301 struct region_info *r;
@@ -1344,7 +1349,7 @@ ofree(struct dir_info *argpool, void *p)
1344 } 1349 }
1345 STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); 1350 STATS_SUB(pool->malloc_guarded, mopts.malloc_guard);
1346 } 1351 }
1347 unmap(pool, p, PAGEROUND(sz)); 1352 unmap(pool, p, PAGEROUND(sz), clear);
1348 delete(pool, r); 1353 delete(pool, r);
1349 } else { 1354 } else {
1350 void *tmp; 1355 void *tmp;
@@ -1353,7 +1358,7 @@ ofree(struct dir_info *argpool, void *p)
1353 /* Delayed free or canaries? Extra check */ 1358 /* Delayed free or canaries? Extra check */
1354 if (!mopts.malloc_freenow || mopts.chunk_canaries) 1359 if (!mopts.malloc_freenow || mopts.chunk_canaries)
1355 find_chunknum(pool, r, p, mopts.chunk_canaries); 1360 find_chunknum(pool, r, p, mopts.chunk_canaries);
1356 if (!mopts.malloc_freenow) { 1361 if (!clear && !mopts.malloc_freenow) {
1357 if (mopts.malloc_junk && sz > 0) 1362 if (mopts.malloc_junk && sz > 0)
1358 memset(p, SOME_FREEJUNK, sz); 1363 memset(p, SOME_FREEJUNK, sz);
1359 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; 1364 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
@@ -1365,8 +1370,8 @@ ofree(struct dir_info *argpool, void *p)
1365 validate_junk(pool, p); 1370 validate_junk(pool, p);
1366 pool->delayed_chunks[i] = tmp; 1371 pool->delayed_chunks[i] = tmp;
1367 } else { 1372 } else {
1368 if (mopts.malloc_junk && sz > 0) 1373 if ((clear || mopts.malloc_junk) && sz > 0)
1369 memset(p, SOME_FREEJUNK, sz); 1374 memset(p, clear ? 0 : SOME_FREEJUNK, sz);
1370 } 1375 }
1371 if (p != NULL) { 1376 if (p != NULL) {
1372 r = find(pool, p); 1377 r = find(pool, p);
@@ -1404,7 +1409,7 @@ free(void *ptr)
1404 malloc_recurse(d); 1409 malloc_recurse(d);
1405 return; 1410 return;
1406 } 1411 }
1407 ofree(d, ptr); 1412 ofree(d, ptr, 0);
1408 d->active--; 1413 d->active--;
1409 _MALLOC_UNLOCK(d->mutex); 1414 _MALLOC_UNLOCK(d->mutex);
1410 errno = saved_errno; 1415 errno = saved_errno;
@@ -1528,7 +1533,7 @@ gotit:
1528 PROT_NONE)) 1533 PROT_NONE))
1529 wrterror(pool, "mprotect"); 1534 wrterror(pool, "mprotect");
1530 } 1535 }
1531 unmap(pool, (char *)r->p + rnewsz, roldsz - rnewsz); 1536 unmap(pool, (char *)r->p + rnewsz, roldsz - rnewsz, 0);
1532 r->size = gnewsz; 1537 r->size = gnewsz;
1533 if (MALLOC_MOVE_COND(gnewsz)) { 1538 if (MALLOC_MOVE_COND(gnewsz)) {
1534 void *pp = MALLOC_MOVE(r->p, gnewsz); 1539 void *pp = MALLOC_MOVE(r->p, gnewsz);
@@ -1584,7 +1589,7 @@ gotit:
1584 } 1589 }
1585 if (newsz != 0 && oldsz != 0) 1590 if (newsz != 0 && oldsz != 0)
1586 memcpy(q, p, oldsz < newsz ? oldsz : newsz); 1591 memcpy(q, p, oldsz < newsz ? oldsz : newsz);
1587 ofree(pool, p); 1592 ofree(pool, p, 0);
1588 ret = q; 1593 ret = q;
1589 } else { 1594 } else {
1590 /* oldsz == newsz */ 1595 /* oldsz == newsz */
@@ -1682,6 +1687,189 @@ calloc(size_t nmemb, size_t size)
1682/*DEF_STRONG(calloc);*/ 1687/*DEF_STRONG(calloc);*/
1683 1688
1684static void * 1689static void *
1690orecallocarray(struct dir_info *argpool, void *p, size_t oldsize,
1691 size_t newsize, void *f)
1692{
1693 struct dir_info *pool;
1694 struct region_info *r;
1695 void *newptr;
1696 size_t sz;
1697 int i;
1698
1699 pool = argpool;
1700
1701 if (p == NULL)
1702 return omalloc(pool, newsize, 1, f);
1703
1704 r = find(pool, p);
1705 if (r == NULL) {
1706 if (mopts.malloc_mt) {
1707 for (i = 0; i < _MALLOC_MUTEXES; i++) {
1708 if (i == argpool->mutex)
1709 continue;
1710 pool->active--;
1711 _MALLOC_UNLOCK(pool->mutex);
1712 pool = mopts.malloc_pool[i];
1713 _MALLOC_LOCK(pool->mutex);
1714 pool->active++;
1715 r = find(pool, p);
1716 if (r != NULL)
1717 break;
1718 }
1719 }
1720 if (r == NULL)
1721 wrterror(pool, "bogus pointer (double free?) %p", p);
1722 }
1723
1724 REALSIZE(sz, r);
1725 if (sz <= MALLOC_MAXCHUNK) {
1726 if (mopts.chunk_canaries) {
1727 struct chunk_info *info = (struct chunk_info *)r->size;
1728 uint32_t chunknum = find_chunknum(pool, r, p, 0);
1729
1730 if (info->bits[info->offset + chunknum] != oldsize)
1731 wrterror(pool, "recorded old size %hu != %zu",
1732 info->bits[info->offset + chunknum],
1733 oldsize);
1734 }
1735 } else if (oldsize != sz - mopts.malloc_guard)
1736 wrterror(pool, "recorded old size %zu != %zu", oldsize,
1737 sz - mopts.malloc_guard);
1738
1739 newptr = omalloc(pool, newsize, 0, f);
1740 if (newptr == NULL)
1741 goto done;
1742
1743 if (newsize > oldsize) {
1744 memcpy(newptr, p, oldsize);
1745 memset((char *)newptr + oldsize, 0, newsize - oldsize);
1746 } else
1747 memcpy(newptr, p, newsize);
1748
1749 ofree(pool, p, 1);
1750
1751done:
1752 if (argpool != pool) {
1753 pool->active--;
1754 _MALLOC_UNLOCK(pool->mutex);
1755 _MALLOC_LOCK(argpool->mutex);
1756 argpool->active++;
1757 }
1758
1759 return newptr;
1760}
1761
1762static void *
1763recallocarray_p(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
1764{
1765 size_t oldsize, newsize;
1766 void *newptr;
1767
1768 if (ptr == NULL)
1769 return calloc(newnmemb, size);
1770
1771 if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1772 newnmemb > 0 && SIZE_MAX / newnmemb < size) {
1773 errno = ENOMEM;
1774 return NULL;
1775 }
1776 newsize = newnmemb * size;
1777
1778 if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1779 oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
1780 errno = EINVAL;
1781 return NULL;
1782 }
1783 oldsize = oldnmemb * size;
1784
1785 /*
1786 * Don't bother too much if we're shrinking just a bit,
1787 * we do not shrink for series of small steps, oh well.
1788 */
1789 if (newsize <= oldsize) {
1790 size_t d = oldsize - newsize;
1791
1792 if (d < oldsize / 2 && d < getpagesize()) {
1793 memset((char *)ptr + newsize, 0, d);
1794 return ptr;
1795 }
1796 }
1797
1798 newptr = malloc(newsize);
1799 if (newptr == NULL)
1800 return NULL;
1801
1802 if (newsize > oldsize) {
1803 memcpy(newptr, ptr, oldsize);
1804 memset((char *)newptr + oldsize, 0, newsize - oldsize);
1805 } else
1806 memcpy(newptr, ptr, newsize);
1807
1808 explicit_bzero(ptr, oldsize);
1809 free(ptr);
1810
1811 return newptr;
1812}
1813
1814void *
1815recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
1816{
1817 struct dir_info *d;
1818 size_t oldsize = 0, newsize;
1819 void *r;
1820 int saved_errno = errno;
1821
1822 if (!mopts.internal_recallocarray)
1823 return recallocarray_p(ptr, oldnmemb, newnmemb, size);
1824
1825 d = getpool();
1826 if (d == NULL) {
1827 _malloc_init(0);
1828 d = getpool();
1829 }
1830
1831 _MALLOC_LOCK(d->mutex);
1832 d->func = "recallocarray";
1833
1834 if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1835 newnmemb > 0 && SIZE_MAX / newnmemb < size) {
1836 _MALLOC_UNLOCK(d->mutex);
1837 if (mopts.malloc_xmalloc)
1838 wrterror(d, "out of memory");
1839 errno = ENOMEM;
1840 return NULL;
1841 }
1842 newsize = newnmemb * size;
1843
1844 if (ptr != NULL) {
1845 if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1846 oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
1847 _MALLOC_UNLOCK(d->mutex);
1848 errno = EINVAL;
1849 return NULL;
1850 }
1851 oldsize = oldnmemb * size;
1852 }
1853
1854 if (d->active++) {
1855 malloc_recurse(d);
1856 return NULL;
1857 }
1858
1859 r = orecallocarray(d, ptr, oldsize, newsize, CALLER);
1860
1861 d->active--;
1862 _MALLOC_UNLOCK(d->mutex);
1863 if (r == NULL && mopts.malloc_xmalloc)
1864 wrterror(d, "out of memory");
1865 if (r != NULL)
1866 errno = saved_errno;
1867 return r;
1868}
1869DEF_WEAK(recallocarray);
1870
1871
1872static void *
1685mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) 1873mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill)
1686{ 1874{
1687 char *p, *q; 1875 char *p, *q;
@@ -1746,7 +1934,7 @@ omemalign(struct dir_info *pool, size_t alignment, size_t sz, int zero_fill, voi
1746 } 1934 }
1747 1935
1748 if (insert(pool, p, sz, f)) { 1936 if (insert(pool, p, sz, f)) {
1749 unmap(pool, p, psz); 1937 unmap(pool, p, psz, 0);
1750 errno = ENOMEM; 1938 errno = ENOMEM;
1751 return NULL; 1939 return NULL;
1752 } 1940 }
@@ -2069,8 +2257,9 @@ malloc_exit(void)
2069 __progname); 2257 __progname);
2070 write(fd, buf, strlen(buf)); 2258 write(fd, buf, strlen(buf));
2071 snprintf(buf, sizeof(buf), 2259 snprintf(buf, sizeof(buf),
2072 "MT=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", 2260 "MT=%d IRC=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n",
2073 mopts.malloc_mt, mopts.malloc_freenow, 2261 mopts.malloc_mt, mopts.internal_recallocarray,
2262 mopts.malloc_freenow,
2074 mopts.malloc_freeunmap, mopts.malloc_junk, 2263 mopts.malloc_freeunmap, mopts.malloc_junk,
2075 mopts.malloc_realloc, mopts.malloc_xmalloc, 2264 mopts.malloc_realloc, mopts.malloc_xmalloc,
2076 mopts.chunk_canaries, mopts.malloc_cache, 2265 mopts.chunk_canaries, mopts.malloc_cache,