summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/libc/include/thread_private.h21
-rw-r--r--src/lib/libc/stdlib/malloc.c263
2 files changed, 190 insertions, 94 deletions
diff --git a/src/lib/libc/include/thread_private.h b/src/lib/libc/include/thread_private.h
index c2e0cf0b3f..81caaaae68 100644
--- a/src/lib/libc/include/thread_private.h
+++ b/src/lib/libc/include/thread_private.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: thread_private.h,v 1.27 2016/05/07 19:05:22 guenther Exp $ */ 1/* $OpenBSD: thread_private.h,v 1.28 2016/09/01 10:41:02 otto Exp $ */
2 2
3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ 3/* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */
4 4
@@ -7,6 +7,9 @@
7 7
8#include <stdio.h> /* for FILE and __isthreaded */ 8#include <stdio.h> /* for FILE and __isthreaded */
9 9
10#define _MALLOC_MUTEXES 4
11void _malloc_init(int);
12
10/* 13/*
11 * The callbacks needed by libc to handle the threaded case. 14 * The callbacks needed by libc to handle the threaded case.
12 * NOTE: Bump the version when you change the struct contents! 15 * NOTE: Bump the version when you change the struct contents!
@@ -72,8 +75,8 @@ struct thread_callbacks {
72 void (*tc_flockfile)(FILE *); 75 void (*tc_flockfile)(FILE *);
73 int (*tc_ftrylockfile)(FILE *); 76 int (*tc_ftrylockfile)(FILE *);
74 void (*tc_funlockfile)(FILE *); 77 void (*tc_funlockfile)(FILE *);
75 void (*tc_malloc_lock)(void); 78 void (*tc_malloc_lock)(int);
76 void (*tc_malloc_unlock)(void); 79 void (*tc_malloc_unlock)(int);
77 void (*tc_atexit_lock)(void); 80 void (*tc_atexit_lock)(void);
78 void (*tc_atexit_unlock)(void); 81 void (*tc_atexit_unlock)(void);
79 void (*tc_atfork_lock)(void); 82 void (*tc_atfork_lock)(void);
@@ -137,8 +140,8 @@ extern void *__THREAD_NAME(serv_mutex);
137#define _MUTEX_LOCK(mutex) do {} while (0) 140#define _MUTEX_LOCK(mutex) do {} while (0)
138#define _MUTEX_UNLOCK(mutex) do {} while (0) 141#define _MUTEX_UNLOCK(mutex) do {} while (0)
139#define _MUTEX_DESTROY(mutex) do {} while (0) 142#define _MUTEX_DESTROY(mutex) do {} while (0)
140#define _MALLOC_LOCK() do {} while (0) 143#define _MALLOC_LOCK(n) do {} while (0)
141#define _MALLOC_UNLOCK() do {} while (0) 144#define _MALLOC_UNLOCK(n) do {} while (0)
142#define _ATEXIT_LOCK() do {} while (0) 145#define _ATEXIT_LOCK() do {} while (0)
143#define _ATEXIT_UNLOCK() do {} while (0) 146#define _ATEXIT_UNLOCK() do {} while (0)
144#define _ATFORK_LOCK() do {} while (0) 147#define _ATFORK_LOCK() do {} while (0)
@@ -184,15 +187,15 @@ extern void *__THREAD_NAME(serv_mutex);
184/* 187/*
185 * malloc lock/unlock prototypes and definitions 188 * malloc lock/unlock prototypes and definitions
186 */ 189 */
187#define _MALLOC_LOCK() \ 190#define _MALLOC_LOCK(n) \
188 do { \ 191 do { \
189 if (__isthreaded) \ 192 if (__isthreaded) \
190 _thread_cb.tc_malloc_lock(); \ 193 _thread_cb.tc_malloc_lock(n); \
191 } while (0) 194 } while (0)
192#define _MALLOC_UNLOCK() \ 195#define _MALLOC_UNLOCK(n) \
193 do { \ 196 do { \
194 if (__isthreaded) \ 197 if (__isthreaded) \
195 _thread_cb.tc_malloc_unlock(); \ 198 _thread_cb.tc_malloc_unlock(n); \
196 } while (0) 199 } while (0)
197 200
198#define _ATEXIT_LOCK() \ 201#define _ATEXIT_LOCK() \
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index c84b7c8ba3..ce869412f5 100644
--- a/src/lib/libc/stdlib/malloc.c
+++ b/src/lib/libc/stdlib/malloc.c
@@ -1,6 +1,6 @@
1/* $OpenBSD: malloc.c,v 1.194 2016/09/01 10:20:22 tedu Exp $ */ 1/* $OpenBSD: malloc.c,v 1.195 2016/09/01 10:41:02 otto Exp $ */
2/* 2/*
3 * Copyright (c) 2008, 2010, 2011 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>
5 * Copyright (c) 2008 Damien Miller <djm@openbsd.org> 5 * Copyright (c) 2008 Damien Miller <djm@openbsd.org>
6 * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org> 6 * Copyright (c) 2000 Poul-Henning Kamp <phk@FreeBSD.org>
@@ -43,6 +43,7 @@
43#endif 43#endif
44 44
45#include "thread_private.h" 45#include "thread_private.h"
46#include <tib.h>
46 47
47#if defined(__mips64__) 48#if defined(__mips64__)
48#define MALLOC_PAGESHIFT (14U) 49#define MALLOC_PAGESHIFT (14U)
@@ -118,6 +119,7 @@ struct dir_info {
118 void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1]; 119 void *delayed_chunks[MALLOC_DELAYED_CHUNK_MASK + 1];
119 size_t rbytesused; /* random bytes used */ 120 size_t rbytesused; /* random bytes used */
120 char *func; /* current function */ 121 char *func; /* current function */
122 int mutex;
121 u_char rbytes[32]; /* random bytes */ 123 u_char rbytes[32]; /* random bytes */
122 u_short chunk_start; 124 u_short chunk_start;
123#ifdef MALLOC_STATS 125#ifdef MALLOC_STATS
@@ -167,7 +169,8 @@ struct chunk_info {
167}; 169};
168 170
169struct malloc_readonly { 171struct malloc_readonly {
170 struct dir_info *malloc_pool; /* Main bookkeeping information */ 172 struct dir_info *malloc_pool[_MALLOC_MUTEXES]; /* Main bookkeeping information */
173 int malloc_mt; /* multi-threaded mode? */
171 int malloc_freenow; /* Free quickly - disable chunk rnd */ 174 int malloc_freenow; /* Free quickly - disable chunk rnd */
172 int malloc_freeunmap; /* mprotect free pages PROT_NONE? */ 175 int malloc_freeunmap; /* mprotect free pages PROT_NONE? */
173 int malloc_hint; /* call madvice on free pages? */ 176 int malloc_hint; /* call madvice on free pages? */
@@ -191,14 +194,13 @@ static union {
191 u_char _pad[MALLOC_PAGESIZE]; 194 u_char _pad[MALLOC_PAGESIZE];
192} malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE))); 195} malloc_readonly __attribute__((aligned(MALLOC_PAGESIZE)));
193#define mopts malloc_readonly.mopts 196#define mopts malloc_readonly.mopts
194#define getpool() mopts.malloc_pool
195 197
196char *malloc_options; /* compile-time options */ 198char *malloc_options; /* compile-time options */
197 199
198static u_char getrbyte(struct dir_info *d); 200static u_char getrbyte(struct dir_info *d);
199 201
200#ifdef MALLOC_STATS 202#ifdef MALLOC_STATS
201void malloc_dump(int); 203void malloc_dump(int, struct dir_info *);
202PROTO_NORMAL(malloc_dump); 204PROTO_NORMAL(malloc_dump);
203static void malloc_exit(void); 205static void malloc_exit(void);
204#define CALLER __builtin_return_address(0) 206#define CALLER __builtin_return_address(0)
@@ -216,17 +218,17 @@ static void malloc_exit(void);
216static inline void 218static inline void
217_MALLOC_LEAVE(struct dir_info *d) 219_MALLOC_LEAVE(struct dir_info *d)
218{ 220{
219 if (__isthreaded) { 221 if (mopts.malloc_mt) {
220 d->active--; 222 d->active--;
221 _MALLOC_UNLOCK(); 223 _MALLOC_UNLOCK(d->mutex);
222 } 224 }
223} 225}
224 226
225static inline void 227static inline void
226_MALLOC_ENTER(struct dir_info *d) 228_MALLOC_ENTER(struct dir_info *d)
227{ 229{
228 if (__isthreaded) { 230 if (mopts.malloc_mt) {
229 _MALLOC_LOCK(); 231 _MALLOC_LOCK(d->mutex);
230 d->active++; 232 d->active++;
231 } 233 }
232} 234}
@@ -247,14 +249,24 @@ hash(void *p)
247 return sum; 249 return sum;
248} 250}
249 251
250__dead static void 252static inline
253struct dir_info *getpool(void)
254{
255 if (!mopts.malloc_mt)
256 return mopts.malloc_pool[0];
257 else
258 return mopts.malloc_pool[TIB_GET()->tib_tid &
259 (_MALLOC_MUTEXES - 1)];
260}
261
262static __dead void
251wrterror(struct dir_info *d, char *msg, void *p) 263wrterror(struct dir_info *d, char *msg, void *p)
252{ 264{
253 char *q = " error: "; 265 char *q = " error: ";
254 struct iovec iov[7]; 266 struct iovec iov[7];
255 char pidbuf[20]; 267 char pidbuf[20];
256 char buf[20]; 268 char buf[20];
257 int saved_errno = errno; 269 int saved_errno = errno, i;
258 270
259 iov[0].iov_base = __progname; 271 iov[0].iov_base = __progname;
260 iov[0].iov_len = strlen(__progname); 272 iov[0].iov_len = strlen(__progname);
@@ -285,7 +297,8 @@ wrterror(struct dir_info *d, char *msg, void *p)
285 297
286#ifdef MALLOC_STATS 298#ifdef MALLOC_STATS
287 if (mopts.malloc_stats) 299 if (mopts.malloc_stats)
288 malloc_dump(STDERR_FILENO); 300 for (i = 0; i < _MALLOC_MUTEXES; i++)
301 malloc_dump(STDERR_FILENO, mopts.malloc_pool[i]);
289#endif /* MALLOC_STATS */ 302#endif /* MALLOC_STATS */
290 303
291 errno = saved_errno; 304 errno = saved_errno;
@@ -413,6 +426,7 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill)
413 wrterror(d, "internal struct corrupt", NULL); 426 wrterror(d, "internal struct corrupt", NULL);
414 if (sz != PAGEROUND(sz)) 427 if (sz != PAGEROUND(sz))
415 wrterror(d, "map round", NULL); 428 wrterror(d, "map round", NULL);
429
416 if (!hint && psz > d->free_regions_size) { 430 if (!hint && psz > d->free_regions_size) {
417 _MALLOC_LEAVE(d); 431 _MALLOC_LEAVE(d);
418 p = MMAP(sz); 432 p = MMAP(sz);
@@ -570,16 +584,11 @@ omalloc_parseopt(char opt)
570 } 584 }
571} 585}
572 586
573/* 587static void
574 * Initialize a dir_info, which should have been cleared by caller 588omalloc_init(void)
575 */
576static int
577omalloc_init(struct dir_info **dp)
578{ 589{
579 char *p, *q, b[64]; 590 char *p, *q, b[64];
580 int i, j; 591 int i, j;
581 size_t d_avail, regioninfo_size;
582 struct dir_info *d;
583 592
584 /* 593 /*
585 * Default options 594 * Default options
@@ -642,6 +651,18 @@ omalloc_init(struct dir_info **dp)
642 651
643 arc4random_buf(&mopts.malloc_chunk_canary, 652 arc4random_buf(&mopts.malloc_chunk_canary,
644 sizeof(mopts.malloc_chunk_canary)); 653 sizeof(mopts.malloc_chunk_canary));
654}
655
656/*
657 * Initialize a dir_info, which should have been cleared by caller
658 */
659static void
660omalloc_poolinit(struct dir_info **dp)
661{
662 void *p;
663 size_t d_avail, regioninfo_size;
664 struct dir_info *d;
665 int i, j;
645 666
646 /* 667 /*
647 * Allocate dir_info with a guard page on either side. Also 668 * Allocate dir_info with a guard page on either side. Also
@@ -649,7 +670,7 @@ omalloc_init(struct dir_info **dp)
649 * lies (subject to alignment by 1 << MALLOC_MINSHIFT) 670 * lies (subject to alignment by 1 << MALLOC_MINSHIFT)
650 */ 671 */
651 if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED) 672 if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED)
652 return -1; 673 wrterror(NULL, "malloc init mmap failed", NULL);
653 mprotect(p, MALLOC_PAGESIZE, PROT_NONE); 674 mprotect(p, MALLOC_PAGESIZE, PROT_NONE);
654 mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ, 675 mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ,
655 MALLOC_PAGESIZE, PROT_NONE); 676 MALLOC_PAGESIZE, PROT_NONE);
@@ -661,9 +682,10 @@ omalloc_init(struct dir_info **dp)
661 d->regions_free = d->regions_total = MALLOC_INITIAL_REGIONS; 682 d->regions_free = d->regions_total = MALLOC_INITIAL_REGIONS;
662 regioninfo_size = d->regions_total * sizeof(struct region_info); 683 regioninfo_size = d->regions_total * sizeof(struct region_info);
663 d->r = MMAP(regioninfo_size); 684 d->r = MMAP(regioninfo_size);
664 if (d->r == MAP_FAILED) 685 if (d->r == MAP_FAILED) {
686 d->regions_total = 0;
665 wrterror(NULL, "malloc init mmap failed", NULL); 687 wrterror(NULL, "malloc init mmap failed", NULL);
666 688 }
667 for (i = 0; i <= MALLOC_MAXSHIFT; i++) { 689 for (i = 0; i <= MALLOC_MAXSHIFT; i++) {
668 LIST_INIT(&d->chunk_info_list[i]); 690 LIST_INIT(&d->chunk_info_list[i]);
669 for (j = 0; j < MALLOC_CHUNK_LISTS; j++) 691 for (j = 0; j < MALLOC_CHUNK_LISTS; j++)
@@ -674,15 +696,6 @@ omalloc_init(struct dir_info **dp)
674 d->canary2 = ~d->canary1; 696 d->canary2 = ~d->canary1;
675 697
676 *dp = d; 698 *dp = d;
677
678 /*
679 * Options have been set and will never be reset.
680 * Prevent further tampering with them.
681 */
682 if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0)
683 mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ);
684
685 return 0;
686} 699}
687 700
688static int 701static int
@@ -1172,21 +1185,46 @@ malloc_recurse(struct dir_info *d)
1172 wrterror(d, "recursive call", NULL); 1185 wrterror(d, "recursive call", NULL);
1173 } 1186 }
1174 d->active--; 1187 d->active--;
1175 _MALLOC_UNLOCK(); 1188 _MALLOC_UNLOCK(d->mutex);
1176 errno = EDEADLK; 1189 errno = EDEADLK;
1177} 1190}
1178 1191
1179static int 1192void
1180malloc_init(void) 1193_malloc_init(int from_rthreads)
1181{ 1194{
1182 if (omalloc_init(&mopts.malloc_pool)) { 1195 int i, max;
1183 _MALLOC_UNLOCK(); 1196 struct dir_info *d;
1184 if (mopts.malloc_xmalloc) 1197
1185 wrterror(NULL, "out of memory", NULL); 1198 _MALLOC_LOCK(0);
1186 errno = ENOMEM; 1199 if (!from_rthreads && mopts.malloc_pool[0]) {
1187 return -1; 1200 _MALLOC_UNLOCK(0);
1201 return;
1188 } 1202 }
1189 return 0; 1203 if (!mopts.malloc_canary)
1204 omalloc_init();
1205
1206 max = from_rthreads ? _MALLOC_MUTEXES : 1;
1207 if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0)
1208 mprotect(&malloc_readonly, sizeof(malloc_readonly),
1209 PROT_READ | PROT_WRITE);
1210 for (i = 0; i < max; i++) {
1211 if (mopts.malloc_pool[i])
1212 continue;
1213 omalloc_poolinit(&d);
1214 d->mutex = i;
1215 mopts.malloc_pool[i] = d;
1216 }
1217
1218 if (from_rthreads)
1219 mopts.malloc_mt = 1;
1220
1221 /*
1222 * Options have been set and will never be reset.
1223 * Prevent further tampering with them.
1224 */
1225 if (((uintptr_t)&malloc_readonly & MALLOC_PAGEMASK) == 0)
1226 mprotect(&malloc_readonly, sizeof(malloc_readonly), PROT_READ);
1227 _MALLOC_UNLOCK(0);
1190} 1228}
1191 1229
1192void * 1230void *
@@ -1196,13 +1234,12 @@ malloc(size_t size)
1196 struct dir_info *d; 1234 struct dir_info *d;
1197 int saved_errno = errno; 1235 int saved_errno = errno;
1198 1236
1199 _MALLOC_LOCK();
1200 d = getpool(); 1237 d = getpool();
1201 if (d == NULL) { 1238 if (d == NULL) {
1202 if (malloc_init() != 0) 1239 _malloc_init(0);
1203 return NULL;
1204 d = getpool(); 1240 d = getpool();
1205 } 1241 }
1242 _MALLOC_LOCK(d->mutex);
1206 d->func = "malloc():"; 1243 d->func = "malloc():";
1207 1244
1208 if (d->active++) { 1245 if (d->active++) {
@@ -1213,7 +1250,7 @@ malloc(size_t size)
1213 size += mopts.malloc_canaries; 1250 size += mopts.malloc_canaries;
1214 r = omalloc(d, size, 0, CALLER); 1251 r = omalloc(d, size, 0, CALLER);
1215 d->active--; 1252 d->active--;
1216 _MALLOC_UNLOCK(); 1253 _MALLOC_UNLOCK(d->mutex);
1217 if (r == NULL && mopts.malloc_xmalloc) 1254 if (r == NULL && mopts.malloc_xmalloc)
1218 wrterror(d, "out of memory", NULL); 1255 wrterror(d, "out of memory", NULL);
1219 if (r != NULL) 1256 if (r != NULL)
@@ -1244,14 +1281,34 @@ validate_junk(struct dir_info *pool, void *p) {
1244} 1281}
1245 1282
1246static void 1283static void
1247ofree(struct dir_info *pool, void *p) 1284ofree(struct dir_info *argpool, void *p)
1248{ 1285{
1286 struct dir_info *pool;
1249 struct region_info *r; 1287 struct region_info *r;
1250 size_t sz; 1288 size_t sz;
1289 int i;
1251 1290
1291 pool = argpool;
1252 r = find(pool, p); 1292 r = find(pool, p);
1253 if (r == NULL) 1293 if (r == NULL) {
1254 wrterror(pool, "bogus pointer (double free?)", p); 1294 if (mopts.malloc_mt) {
1295 for (i = 0; i < _MALLOC_MUTEXES; i++) {
1296 if (i == argpool->mutex)
1297 continue;
1298 pool->active--;
1299 _MALLOC_UNLOCK(pool->mutex);
1300 pool = mopts.malloc_pool[i];
1301 _MALLOC_LOCK(pool->mutex);
1302 pool->active++;
1303 r = find(pool, p);
1304 if (r != NULL)
1305 break;
1306 }
1307 }
1308 if (r == NULL)
1309 wrterror(pool, "bogus pointer (double free?)", p);
1310 }
1311
1255 REALSIZE(sz, r); 1312 REALSIZE(sz, r);
1256 if (sz > MALLOC_MAXCHUNK) { 1313 if (sz > MALLOC_MAXCHUNK) {
1257 if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE - 1314 if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE -
@@ -1294,7 +1351,7 @@ ofree(struct dir_info *pool, void *p)
1294 memset(p, SOME_FREEJUNK, sz - mopts.malloc_canaries); 1351 memset(p, SOME_FREEJUNK, sz - mopts.malloc_canaries);
1295 if (!mopts.malloc_freenow) { 1352 if (!mopts.malloc_freenow) {
1296 if (find_chunknum(pool, r, p) == -1) 1353 if (find_chunknum(pool, r, p) == -1)
1297 return; 1354 goto done;
1298 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK; 1355 i = getrbyte(pool) & MALLOC_DELAYED_CHUNK_MASK;
1299 tmp = p; 1356 tmp = p;
1300 p = pool->delayed_chunks[i]; 1357 p = pool->delayed_chunks[i];
@@ -1311,6 +1368,13 @@ ofree(struct dir_info *pool, void *p)
1311 free_bytes(pool, r, p); 1368 free_bytes(pool, r, p);
1312 } 1369 }
1313 } 1370 }
1371done:
1372 if (argpool != pool) {
1373 pool->active--;
1374 _MALLOC_UNLOCK(pool->mutex);
1375 _MALLOC_LOCK(argpool->mutex);
1376 argpool->active++;
1377 }
1314} 1378}
1315 1379
1316void 1380void
@@ -1323,12 +1387,10 @@ free(void *ptr)
1323 if (ptr == NULL) 1387 if (ptr == NULL)
1324 return; 1388 return;
1325 1389
1326 _MALLOC_LOCK();
1327 d = getpool(); 1390 d = getpool();
1328 if (d == NULL) { 1391 if (d == NULL)
1329 _MALLOC_UNLOCK();
1330 wrterror(d, "free() called before allocation", NULL); 1392 wrterror(d, "free() called before allocation", NULL);
1331 } 1393 _MALLOC_LOCK(d->mutex);
1332 d->func = "free():"; 1394 d->func = "free():";
1333 if (d->active++) { 1395 if (d->active++) {
1334 malloc_recurse(d); 1396 malloc_recurse(d);
@@ -1336,28 +1398,49 @@ free(void *ptr)
1336 } 1398 }
1337 ofree(d, ptr); 1399 ofree(d, ptr);
1338 d->active--; 1400 d->active--;
1339 _MALLOC_UNLOCK(); 1401 _MALLOC_UNLOCK(d->mutex);
1340 errno = saved_errno; 1402 errno = saved_errno;
1341} 1403}
1342/*DEF_STRONG(free);*/ 1404/*DEF_STRONG(free);*/
1343 1405
1344 1406
1345static void * 1407static void *
1346orealloc(struct dir_info *pool, void *p, size_t newsz, void *f) 1408orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f)
1347{ 1409{
1410 struct dir_info *pool;
1348 struct region_info *r; 1411 struct region_info *r;
1349 size_t oldsz, goldsz, gnewsz; 1412 size_t oldsz, goldsz, gnewsz;
1350 void *q; 1413 void *q, *ret;
1414 int i;
1415
1416 pool = argpool;
1351 1417
1352 if (p == NULL) 1418 if (p == NULL)
1353 return omalloc(pool, newsz, 0, f); 1419 return omalloc(pool, newsz, 0, f);
1354 1420
1355 r = find(pool, p); 1421 r = find(pool, p);
1356 if (r == NULL) 1422 if (r == NULL) {
1357 wrterror(pool, "bogus pointer (double free?)", p); 1423 if (mopts.malloc_mt) {
1424 for (i = 0; i < _MALLOC_MUTEXES; i++) {
1425 if (i == argpool->mutex)
1426 continue;
1427 pool->active--;
1428 _MALLOC_UNLOCK(pool->mutex);
1429 pool = mopts.malloc_pool[i];
1430 _MALLOC_LOCK(pool->mutex);
1431 pool->active++;
1432 r = find(pool, p);
1433 if (r != NULL)
1434 break;
1435 }
1436 }
1437 if (r == NULL)
1438 wrterror(pool, "bogus pointer (double free?)", p);
1439 }
1358 if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { 1440 if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) {
1359 errno = ENOMEM; 1441 errno = ENOMEM;
1360 return NULL; 1442 ret = NULL;
1443 goto done;
1361 } 1444 }
1362 1445
1363 REALSIZE(oldsz, r); 1446 REALSIZE(oldsz, r);
@@ -1400,7 +1483,8 @@ gotit:
1400 r->size = newsz; 1483 r->size = newsz;
1401 STATS_SETF(r, f); 1484 STATS_SETF(r, f);
1402 STATS_INC(pool->cheap_reallocs); 1485 STATS_INC(pool->cheap_reallocs);
1403 return p; 1486 ret = p;
1487 goto done;
1404 } else if (q != MAP_FAILED) { 1488 } else if (q != MAP_FAILED) {
1405 if (munmap(q, needed)) 1489 if (munmap(q, needed))
1406 wrterror(pool, "munmap", q); 1490 wrterror(pool, "munmap", q);
@@ -1420,14 +1504,16 @@ gotit:
1420 unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); 1504 unmap(pool, (char *)p + rnewsz, roldsz - rnewsz);
1421 r->size = gnewsz; 1505 r->size = gnewsz;
1422 STATS_SETF(r, f); 1506 STATS_SETF(r, f);
1423 return p; 1507 ret = p;
1508 goto done;
1424 } else { 1509 } else {
1425 if (newsz > oldsz && mopts.malloc_junk == 2) 1510 if (newsz > oldsz && mopts.malloc_junk == 2)
1426 memset((char *)p + newsz, SOME_JUNK, 1511 memset((char *)p + newsz, SOME_JUNK,
1427 rnewsz - mopts.malloc_guard - newsz); 1512 rnewsz - mopts.malloc_guard - newsz);
1428 r->size = gnewsz; 1513 r->size = gnewsz;
1429 STATS_SETF(r, f); 1514 STATS_SETF(r, f);
1430 return p; 1515 ret = p;
1516 goto done;
1431 } 1517 }
1432 } 1518 }
1433 if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) { 1519 if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) {
@@ -1439,11 +1525,13 @@ gotit:
1439 memset((char *)p + newsz, SOME_JUNK, usable_oldsz - newsz); 1525 memset((char *)p + newsz, SOME_JUNK, usable_oldsz - newsz);
1440 } 1526 }
1441 STATS_SETF(r, f); 1527 STATS_SETF(r, f);
1442 return p; 1528 ret = p;
1443 } else if (newsz != oldsz || mopts.malloc_realloc) { 1529 } else if (newsz != oldsz || mopts.malloc_realloc) {
1444 q = omalloc(pool, newsz, 0, f); 1530 q = omalloc(pool, newsz, 0, f);
1445 if (q == NULL) 1531 if (q == NULL) {
1446 return NULL; 1532 ret = NULL;
1533 goto done;
1534 }
1447 if (newsz != 0 && oldsz != 0) { 1535 if (newsz != 0 && oldsz != 0) {
1448 size_t copysz = oldsz < newsz ? oldsz : newsz; 1536 size_t copysz = oldsz < newsz ? oldsz : newsz;
1449 if (copysz <= MALLOC_MAXCHUNK) 1537 if (copysz <= MALLOC_MAXCHUNK)
@@ -1451,11 +1539,19 @@ gotit:
1451 memcpy(q, p, copysz); 1539 memcpy(q, p, copysz);
1452 } 1540 }
1453 ofree(pool, p); 1541 ofree(pool, p);
1454 return q; 1542 ret = q;
1455 } else { 1543 } else {
1456 STATS_SETF(r, f); 1544 STATS_SETF(r, f);
1457 return p; 1545 ret = p;
1546 }
1547done:
1548 if (argpool != pool) {
1549 pool->active--;
1550 _MALLOC_UNLOCK(pool->mutex);
1551 _MALLOC_LOCK(argpool->mutex);
1552 argpool->active++;
1458 } 1553 }
1554 return ret;
1459} 1555}
1460 1556
1461void * 1557void *
@@ -1465,13 +1561,12 @@ realloc(void *ptr, size_t size)
1465 void *r; 1561 void *r;
1466 int saved_errno = errno; 1562 int saved_errno = errno;
1467 1563
1468 _MALLOC_LOCK();
1469 d = getpool(); 1564 d = getpool();
1470 if (d == NULL) { 1565 if (d == NULL) {
1471 if (malloc_init() != 0) 1566 _malloc_init(0);
1472 return NULL;
1473 d = getpool(); 1567 d = getpool();
1474 } 1568 }
1569 _MALLOC_LOCK(d->mutex);
1475 d->func = "realloc():"; 1570 d->func = "realloc():";
1476 if (d->active++) { 1571 if (d->active++) {
1477 malloc_recurse(d); 1572 malloc_recurse(d);
@@ -1482,7 +1577,7 @@ realloc(void *ptr, size_t size)
1482 r = orealloc(d, ptr, size, CALLER); 1577 r = orealloc(d, ptr, size, CALLER);
1483 1578
1484 d->active--; 1579 d->active--;
1485 _MALLOC_UNLOCK(); 1580 _MALLOC_UNLOCK(d->mutex);
1486 if (r == NULL && mopts.malloc_xmalloc) 1581 if (r == NULL && mopts.malloc_xmalloc)
1487 wrterror(d, "out of memory", NULL); 1582 wrterror(d, "out of memory", NULL);
1488 if (r != NULL) 1583 if (r != NULL)
@@ -1505,17 +1600,16 @@ calloc(size_t nmemb, size_t size)
1505 void *r; 1600 void *r;
1506 int saved_errno = errno; 1601 int saved_errno = errno;
1507 1602
1508 _MALLOC_LOCK();
1509 d = getpool(); 1603 d = getpool();
1510 if (d == NULL) { 1604 if (d == NULL) {
1511 if (malloc_init() != 0) 1605 _malloc_init(0);
1512 return NULL;
1513 d = getpool(); 1606 d = getpool();
1514 } 1607 }
1608 _MALLOC_LOCK(d->mutex);
1515 d->func = "calloc():"; 1609 d->func = "calloc():";
1516 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && 1610 if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
1517 nmemb > 0 && SIZE_MAX / nmemb < size) { 1611 nmemb > 0 && SIZE_MAX / nmemb < size) {
1518 _MALLOC_UNLOCK(); 1612 _MALLOC_UNLOCK(d->mutex);
1519 if (mopts.malloc_xmalloc) 1613 if (mopts.malloc_xmalloc)
1520 wrterror(d, "out of memory", NULL); 1614 wrterror(d, "out of memory", NULL);
1521 errno = ENOMEM; 1615 errno = ENOMEM;
@@ -1533,7 +1627,7 @@ calloc(size_t nmemb, size_t size)
1533 r = omalloc(d, size, 1, CALLER); 1627 r = omalloc(d, size, 1, CALLER);
1534 1628
1535 d->active--; 1629 d->active--;
1536 _MALLOC_UNLOCK(); 1630 _MALLOC_UNLOCK(d->mutex);
1537 if (r == NULL && mopts.malloc_xmalloc) 1631 if (r == NULL && mopts.malloc_xmalloc)
1538 wrterror(d, "out of memory", NULL); 1632 wrterror(d, "out of memory", NULL);
1539 if (r != NULL) 1633 if (r != NULL)
@@ -1641,13 +1735,12 @@ posix_memalign(void **memptr, size_t alignment, size_t size)
1641 if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *)) 1735 if (((alignment - 1) & alignment) != 0 || alignment < sizeof(void *))
1642 return EINVAL; 1736 return EINVAL;
1643 1737
1644 _MALLOC_LOCK();
1645 d = getpool(); 1738 d = getpool();
1646 if (d == NULL) { 1739 if (d == NULL) {
1647 if (malloc_init() != 0) 1740 _malloc_init(0);
1648 goto err;
1649 d = getpool(); 1741 d = getpool();
1650 } 1742 }
1743 _MALLOC_LOCK(d->mutex);
1651 d->func = "posix_memalign():"; 1744 d->func = "posix_memalign():";
1652 if (d->active++) { 1745 if (d->active++) {
1653 malloc_recurse(d); 1746 malloc_recurse(d);
@@ -1657,7 +1750,7 @@ posix_memalign(void **memptr, size_t alignment, size_t size)
1657 size += mopts.malloc_canaries; 1750 size += mopts.malloc_canaries;
1658 r = omemalign(d, alignment, size, 0, CALLER); 1751 r = omemalign(d, alignment, size, 0, CALLER);
1659 d->active--; 1752 d->active--;
1660 _MALLOC_UNLOCK(); 1753 _MALLOC_UNLOCK(d->mutex);
1661 if (r == NULL) { 1754 if (r == NULL) {
1662 if (mopts.malloc_xmalloc) 1755 if (mopts.malloc_xmalloc)
1663 wrterror(d, "out of memory", NULL); 1756 wrterror(d, "out of memory", NULL);
@@ -1703,7 +1796,7 @@ putleakinfo(void *f, size_t sz, int cnt)
1703 static struct leaknode *page; 1796 static struct leaknode *page;
1704 static int used; 1797 static int used;
1705 1798
1706 if (cnt == 0) 1799 if (cnt == 0 || page == MAP_FAILED)
1707 return; 1800 return;
1708 1801
1709 key.d.f = f; 1802 key.d.f = f;
@@ -1894,9 +1987,8 @@ malloc_dump1(int fd, struct dir_info *d)
1894} 1987}
1895 1988
1896void 1989void
1897malloc_dump(int fd) 1990malloc_dump(int fd, struct dir_info *pool)
1898{ 1991{
1899 struct dir_info *pool = getpool();
1900 int i; 1992 int i;
1901 void *p; 1993 void *p;
1902 struct region_info *r; 1994 struct region_info *r;
@@ -1925,11 +2017,12 @@ static void
1925malloc_exit(void) 2017malloc_exit(void)
1926{ 2018{
1927 static const char q[] = "malloc() warning: Couldn't dump stats\n"; 2019 static const char q[] = "malloc() warning: Couldn't dump stats\n";
1928 int save_errno = errno, fd; 2020 int save_errno = errno, fd, i;
1929 2021
1930 fd = open("malloc.out", O_RDWR|O_APPEND); 2022 fd = open("malloc.out", O_RDWR|O_APPEND);
1931 if (fd != -1) { 2023 if (fd != -1) {
1932 malloc_dump(fd); 2024 for (i = 0; i < _MALLOC_MUTEXES; i++)
2025 malloc_dump(fd, mopts.malloc_pool[i]);
1933 close(fd); 2026 close(fd);
1934 } else 2027 } else
1935 write(STDERR_FILENO, q, sizeof(q) - 1); 2028 write(STDERR_FILENO, q, sizeof(q) - 1);