diff options
Diffstat (limited to 'src/lib/libc/stdlib/malloc.c')
-rw-r--r-- | src/lib/libc/stdlib/malloc.c | 84 |
1 files changed, 72 insertions, 12 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index f2b8b1549b..07c73ca774 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.219 2017/04/06 08:39:47 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.220 2017/04/10 05:45:02 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,7 +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 | int internal_funcs; /* use better recallocarray/freezero? */ |
189 | u_int malloc_cache; /* free pages we cache */ | 189 | u_int malloc_cache; /* free pages we cache */ |
190 | size_t malloc_guard; /* use guard pages after allocations? */ | 190 | size_t malloc_guard; /* use guard pages after allocations? */ |
191 | #ifdef MALLOC_STATS | 191 | #ifdef MALLOC_STATS |
@@ -343,7 +343,14 @@ unmap(struct dir_info *d, void *p, size_t sz, int clear) | |||
343 | if (sz != PAGEROUND(sz)) | 343 | if (sz != PAGEROUND(sz)) |
344 | wrterror(d, "munmap round"); | 344 | wrterror(d, "munmap round"); |
345 | 345 | ||
346 | if (psz > mopts.malloc_cache) { | 346 | rsz = mopts.malloc_cache - d->free_regions_size; |
347 | |||
348 | /* | ||
349 | * normally the cache holds recently freed regions, but if the region | ||
350 | * to unmap is larger than the cache size or we're clearing and the | ||
351 | * cache is full, just munmap | ||
352 | */ | ||
353 | if (psz > mopts.malloc_cache || (clear && rsz == 0)) { | ||
347 | i = munmap(p, sz); | 354 | i = munmap(p, sz); |
348 | if (i) | 355 | if (i) |
349 | wrterror(d, "munmap %p", p); | 356 | wrterror(d, "munmap %p", p); |
@@ -351,7 +358,6 @@ unmap(struct dir_info *d, void *p, size_t sz, int clear) | |||
351 | return; | 358 | return; |
352 | } | 359 | } |
353 | tounmap = 0; | 360 | tounmap = 0; |
354 | rsz = mopts.malloc_cache - d->free_regions_size; | ||
355 | if (psz > rsz) | 361 | if (psz > rsz) |
356 | tounmap = psz - rsz; | 362 | tounmap = psz - rsz; |
357 | offset = getrbyte(d); | 363 | offset = getrbyte(d); |
@@ -1234,7 +1240,7 @@ _malloc_init(int from_rthreads) | |||
1234 | if (from_rthreads) | 1240 | if (from_rthreads) |
1235 | mopts.malloc_mt = 1; | 1241 | mopts.malloc_mt = 1; |
1236 | else | 1242 | else |
1237 | mopts.internal_recallocarray = 1; | 1243 | mopts.internal_funcs = 1; |
1238 | 1244 | ||
1239 | /* | 1245 | /* |
1240 | * Options have been set and will never be reset. | 1246 | * Options have been set and will never be reset. |
@@ -1297,7 +1303,7 @@ validate_junk(struct dir_info *pool, void *p) | |||
1297 | } | 1303 | } |
1298 | 1304 | ||
1299 | static void | 1305 | static void |
1300 | ofree(struct dir_info *argpool, void *p, int clear) | 1306 | ofree(struct dir_info *argpool, void *p, int clear, int check, size_t argsz) |
1301 | { | 1307 | { |
1302 | struct dir_info *pool; | 1308 | struct dir_info *pool; |
1303 | struct region_info *r; | 1309 | struct region_info *r; |
@@ -1326,6 +1332,25 @@ ofree(struct dir_info *argpool, void *p, int clear) | |||
1326 | } | 1332 | } |
1327 | 1333 | ||
1328 | REALSIZE(sz, r); | 1334 | REALSIZE(sz, r); |
1335 | if (check) { | ||
1336 | if (sz <= MALLOC_MAXCHUNK) { | ||
1337 | if (mopts.chunk_canaries) { | ||
1338 | struct chunk_info *info = | ||
1339 | (struct chunk_info *)r->size; | ||
1340 | uint32_t chunknum = | ||
1341 | find_chunknum(pool, r, p, 0); | ||
1342 | |||
1343 | if (info->bits[info->offset + chunknum] != | ||
1344 | argsz) | ||
1345 | wrterror(pool, "recorded old size %hu" | ||
1346 | " != %zu", | ||
1347 | info->bits[info->offset + chunknum], | ||
1348 | argsz); | ||
1349 | } | ||
1350 | } else if (argsz != sz - mopts.malloc_guard) | ||
1351 | wrterror(pool, "recorded old size %zu != %zu", | ||
1352 | sz - mopts.malloc_guard, argsz); | ||
1353 | } | ||
1329 | if (sz > MALLOC_MAXCHUNK) { | 1354 | if (sz > MALLOC_MAXCHUNK) { |
1330 | if (!MALLOC_MOVE_COND(sz)) { | 1355 | if (!MALLOC_MOVE_COND(sz)) { |
1331 | if (r->p != p) | 1356 | if (r->p != p) |
@@ -1411,13 +1436,48 @@ free(void *ptr) | |||
1411 | malloc_recurse(d); | 1436 | malloc_recurse(d); |
1412 | return; | 1437 | return; |
1413 | } | 1438 | } |
1414 | ofree(d, ptr, 0); | 1439 | ofree(d, ptr, 0, 0, 0); |
1415 | d->active--; | 1440 | d->active--; |
1416 | _MALLOC_UNLOCK(d->mutex); | 1441 | _MALLOC_UNLOCK(d->mutex); |
1417 | errno = saved_errno; | 1442 | errno = saved_errno; |
1418 | } | 1443 | } |
1419 | /*DEF_STRONG(free);*/ | 1444 | /*DEF_STRONG(free);*/ |
1420 | 1445 | ||
1446 | static void | ||
1447 | freezero_p(void *ptr, size_t sz) | ||
1448 | { | ||
1449 | explicit_bzero(ptr, sz); | ||
1450 | free(ptr); | ||
1451 | } | ||
1452 | |||
1453 | void | ||
1454 | freezero(void *ptr, size_t sz) | ||
1455 | { | ||
1456 | struct dir_info *d; | ||
1457 | int saved_errno = errno; | ||
1458 | |||
1459 | /* This is legal. */ | ||
1460 | if (ptr == NULL) | ||
1461 | return; | ||
1462 | |||
1463 | if (!mopts.internal_funcs) | ||
1464 | return freezero_p(ptr, sz); | ||
1465 | |||
1466 | d = getpool(); | ||
1467 | if (d == NULL) | ||
1468 | wrterror(d, "freezero() called before allocation"); | ||
1469 | _MALLOC_LOCK(d->mutex); | ||
1470 | d->func = "freezero"; | ||
1471 | if (d->active++) { | ||
1472 | malloc_recurse(d); | ||
1473 | return; | ||
1474 | } | ||
1475 | ofree(d, ptr, 1, 1, sz); | ||
1476 | d->active--; | ||
1477 | _MALLOC_UNLOCK(d->mutex); | ||
1478 | errno = saved_errno; | ||
1479 | } | ||
1480 | DEF_WEAK(freezero); | ||
1421 | 1481 | ||
1422 | static void * | 1482 | static void * |
1423 | orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) | 1483 | orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) |
@@ -1591,7 +1651,7 @@ gotit: | |||
1591 | } | 1651 | } |
1592 | if (newsz != 0 && oldsz != 0) | 1652 | if (newsz != 0 && oldsz != 0) |
1593 | memcpy(q, p, oldsz < newsz ? oldsz : newsz); | 1653 | memcpy(q, p, oldsz < newsz ? oldsz : newsz); |
1594 | ofree(pool, p, 0); | 1654 | ofree(pool, p, 0, 0, 0); |
1595 | ret = q; | 1655 | ret = q; |
1596 | } else { | 1656 | } else { |
1597 | /* oldsz == newsz */ | 1657 | /* oldsz == newsz */ |
@@ -1751,7 +1811,7 @@ orecallocarray(struct dir_info *argpool, void *p, size_t oldsize, | |||
1751 | } else | 1811 | } else |
1752 | memcpy(newptr, p, newsize); | 1812 | memcpy(newptr, p, newsize); |
1753 | 1813 | ||
1754 | ofree(pool, p, 1); | 1814 | ofree(pool, p, 1, 0, 0); |
1755 | 1815 | ||
1756 | done: | 1816 | done: |
1757 | if (argpool != pool) { | 1817 | if (argpool != pool) { |
@@ -1824,7 +1884,7 @@ recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size) | |||
1824 | void *r; | 1884 | void *r; |
1825 | int saved_errno = errno; | 1885 | int saved_errno = errno; |
1826 | 1886 | ||
1827 | if (!mopts.internal_recallocarray) | 1887 | if (!mopts.internal_funcs) |
1828 | return recallocarray_p(ptr, oldnmemb, newnmemb, size); | 1888 | return recallocarray_p(ptr, oldnmemb, newnmemb, size); |
1829 | 1889 | ||
1830 | d = getpool(); | 1890 | d = getpool(); |
@@ -2275,8 +2335,8 @@ malloc_exit(void) | |||
2275 | __progname); | 2335 | __progname); |
2276 | write(fd, buf, strlen(buf)); | 2336 | write(fd, buf, strlen(buf)); |
2277 | snprintf(buf, sizeof(buf), | 2337 | snprintf(buf, sizeof(buf), |
2278 | "MT=%d IRC=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", | 2338 | "MT=%d I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", |
2279 | mopts.malloc_mt, mopts.internal_recallocarray, | 2339 | mopts.malloc_mt, mopts.internal_funcs, |
2280 | mopts.malloc_freenow, | 2340 | mopts.malloc_freenow, |
2281 | mopts.malloc_freeunmap, mopts.malloc_junk, | 2341 | mopts.malloc_freeunmap, mopts.malloc_junk, |
2282 | mopts.malloc_realloc, mopts.malloc_xmalloc, | 2342 | mopts.malloc_realloc, mopts.malloc_xmalloc, |