diff options
Diffstat (limited to 'src/lib/libc/stdlib')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 190 |
1 files changed, 165 insertions, 25 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 025508a335..d82c326914 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.131 2011/05/08 07:08:13 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.132 2011/05/12 09:29:30 otto Exp $ */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> | 3 | * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> |
| 4 | * | 4 | * |
| @@ -43,6 +43,7 @@ | |||
| 43 | #include <unistd.h> | 43 | #include <unistd.h> |
| 44 | 44 | ||
| 45 | #ifdef MALLOC_STATS | 45 | #ifdef MALLOC_STATS |
| 46 | #include <sys/tree.h> | ||
| 46 | #include <fcntl.h> | 47 | #include <fcntl.h> |
| 47 | #endif | 48 | #endif |
| 48 | 49 | ||
| @@ -94,6 +95,9 @@ | |||
| 94 | struct region_info { | 95 | struct region_info { |
| 95 | void *p; /* page; low bits used to mark chunks */ | 96 | void *p; /* page; low bits used to mark chunks */ |
| 96 | uintptr_t size; /* size for pages, or chunk_info pointer */ | 97 | uintptr_t size; /* size for pages, or chunk_info pointer */ |
| 98 | #ifdef MALLOC_STATS | ||
| 99 | void *f; /* where allocated from */ | ||
| 100 | #endif | ||
| 97 | }; | 101 | }; |
| 98 | 102 | ||
| 99 | LIST_HEAD(chunk_head, chunk_info); | 103 | LIST_HEAD(chunk_head, chunk_info); |
| @@ -125,9 +129,11 @@ struct dir_info { | |||
| 125 | size_t cheap_reallocs; | 129 | size_t cheap_reallocs; |
| 126 | #define STATS_INC(x) ((x)++) | 130 | #define STATS_INC(x) ((x)++) |
| 127 | #define STATS_ZERO(x) ((x) = 0) | 131 | #define STATS_ZERO(x) ((x) = 0) |
| 132 | #define STATS_SETF(x,y) ((x)->f = (y)) | ||
| 128 | #else | 133 | #else |
| 129 | #define STATS_INC(x) /* nothing */ | 134 | #define STATS_INC(x) /* nothing */ |
| 130 | #define STATS_ZERO(x) /* nothing */ | 135 | #define STATS_ZERO(x) /* nothing */ |
| 136 | #define STATS_SETF(x,y) /* nothing */ | ||
| 131 | #endif /* MALLOC_STATS */ | 137 | #endif /* MALLOC_STATS */ |
| 132 | u_int32_t canary2; | 138 | u_int32_t canary2; |
| 133 | }; | 139 | }; |
| @@ -195,6 +201,9 @@ extern char *__progname; | |||
| 195 | #ifdef MALLOC_STATS | 201 | #ifdef MALLOC_STATS |
| 196 | void malloc_dump(int); | 202 | void malloc_dump(int); |
| 197 | static void malloc_exit(void); | 203 | static void malloc_exit(void); |
| 204 | #define CALLER __builtin_return_address(0) | ||
| 205 | #else | ||
| 206 | #define CALLER NULL | ||
| 198 | #endif | 207 | #endif |
| 199 | 208 | ||
| 200 | /* low bits of r->p determine size: 0 means >= page size and p->size holding | 209 | /* low bits of r->p determine size: 0 means >= page size and p->size holding |
| @@ -696,7 +705,7 @@ alloc_chunk_info(struct dir_info *d) | |||
| 696 | } | 705 | } |
| 697 | 706 | ||
| 698 | static int | 707 | static int |
| 699 | insert(struct dir_info *d, void *p, size_t sz) | 708 | insert(struct dir_info *d, void *p, size_t sz, void *f) |
| 700 | { | 709 | { |
| 701 | size_t index; | 710 | size_t index; |
| 702 | size_t mask; | 711 | size_t mask; |
| @@ -717,6 +726,9 @@ insert(struct dir_info *d, void *p, size_t sz) | |||
| 717 | } | 726 | } |
| 718 | d->r[index].p = p; | 727 | d->r[index].p = p; |
| 719 | d->r[index].size = sz; | 728 | d->r[index].size = sz; |
| 729 | #ifdef MALLOC_STATS | ||
| 730 | d->r[index].f = f; | ||
| 731 | #endif | ||
| 720 | d->regions_free--; | 732 | d->regions_free--; |
| 721 | return 0; | 733 | return 0; |
| 722 | } | 734 | } |
| @@ -839,7 +851,7 @@ omalloc_make_chunks(struct dir_info *d, int bits) | |||
| 839 | if ((uintptr_t)pp & bits) | 851 | if ((uintptr_t)pp & bits) |
| 840 | wrterror("pp & bits", pp); | 852 | wrterror("pp & bits", pp); |
| 841 | 853 | ||
| 842 | insert(d, (void *)((uintptr_t)pp | bits), (uintptr_t)bp); | 854 | insert(d, (void *)((uintptr_t)pp | bits), (uintptr_t)bp, NULL); |
| 843 | return bp; | 855 | return bp; |
| 844 | } | 856 | } |
| 845 | 857 | ||
| @@ -848,7 +860,7 @@ omalloc_make_chunks(struct dir_info *d, int bits) | |||
| 848 | * Allocate a chunk | 860 | * Allocate a chunk |
| 849 | */ | 861 | */ |
| 850 | static void * | 862 | static void * |
| 851 | malloc_bytes(struct dir_info *d, size_t size) | 863 | malloc_bytes(struct dir_info *d, size_t size, void *f) |
| 852 | { | 864 | { |
| 853 | int i, j; | 865 | int i, j; |
| 854 | size_t k; | 866 | size_t k; |
| @@ -908,6 +920,12 @@ malloc_bytes(struct dir_info *d, size_t size) | |||
| 908 | i = 0; | 920 | i = 0; |
| 909 | } | 921 | } |
| 910 | d->chunk_start += i + 1; | 922 | d->chunk_start += i + 1; |
| 923 | #ifdef MALLOC_STATS | ||
| 924 | if (i == 0) { | ||
| 925 | struct region_info *r = find(d, bp->page); | ||
| 926 | r->f = f; | ||
| 927 | } | ||
| 928 | #endif | ||
| 911 | 929 | ||
| 912 | *lp ^= u; | 930 | *lp ^= u; |
| 913 | 931 | ||
| @@ -980,7 +998,7 @@ free_bytes(struct dir_info *d, struct region_info *r, void *ptr) | |||
| 980 | 998 | ||
| 981 | 999 | ||
| 982 | static void * | 1000 | static void * |
| 983 | omalloc(size_t sz, int zero_fill) | 1001 | omalloc(size_t sz, int zero_fill, void *f) |
| 984 | { | 1002 | { |
| 985 | void *p; | 1003 | void *p; |
| 986 | size_t psz; | 1004 | size_t psz; |
| @@ -997,7 +1015,7 @@ omalloc(size_t sz, int zero_fill) | |||
| 997 | errno = ENOMEM; | 1015 | errno = ENOMEM; |
| 998 | return NULL; | 1016 | return NULL; |
| 999 | } | 1017 | } |
| 1000 | if (insert(g_pool, p, sz)) { | 1018 | if (insert(g_pool, p, sz, f)) { |
| 1001 | unmap(g_pool, p, psz); | 1019 | unmap(g_pool, p, psz); |
| 1002 | errno = ENOMEM; | 1020 | errno = ENOMEM; |
| 1003 | return NULL; | 1021 | return NULL; |
| @@ -1034,7 +1052,7 @@ omalloc(size_t sz, int zero_fill) | |||
| 1034 | 1052 | ||
| 1035 | } else { | 1053 | } else { |
| 1036 | /* takes care of SOME_JUNK */ | 1054 | /* takes care of SOME_JUNK */ |
| 1037 | p = malloc_bytes(g_pool, sz); | 1055 | p = malloc_bytes(g_pool, sz, f); |
| 1038 | if (zero_fill && p != NULL && sz > 0) | 1056 | if (zero_fill && p != NULL && sz > 0) |
| 1039 | memset(p, 0, sz); | 1057 | memset(p, 0, sz); |
| 1040 | } | 1058 | } |
| @@ -1090,7 +1108,7 @@ malloc(size_t size) | |||
| 1090 | malloc_recurse(); | 1108 | malloc_recurse(); |
| 1091 | return NULL; | 1109 | return NULL; |
| 1092 | } | 1110 | } |
| 1093 | r = omalloc(size, mopts.malloc_zero); | 1111 | r = omalloc(size, mopts.malloc_zero, CALLER); |
| 1094 | malloc_active--; | 1112 | malloc_active--; |
| 1095 | _MALLOC_UNLOCK(); | 1113 | _MALLOC_UNLOCK(); |
| 1096 | if (r == NULL && mopts.malloc_xmalloc) { | 1114 | if (r == NULL && mopts.malloc_xmalloc) { |
| @@ -1198,14 +1216,14 @@ free(void *ptr) | |||
| 1198 | 1216 | ||
| 1199 | 1217 | ||
| 1200 | static void * | 1218 | static void * |
| 1201 | orealloc(void *p, size_t newsz) | 1219 | orealloc(void *p, size_t newsz, void *f) |
| 1202 | { | 1220 | { |
| 1203 | struct region_info *r; | 1221 | struct region_info *r; |
| 1204 | size_t oldsz, goldsz, gnewsz; | 1222 | size_t oldsz, goldsz, gnewsz; |
| 1205 | void *q; | 1223 | void *q; |
| 1206 | 1224 | ||
| 1207 | if (p == NULL) | 1225 | if (p == NULL) |
| 1208 | return omalloc(newsz, 0); | 1226 | return omalloc(newsz, 0, f); |
| 1209 | 1227 | ||
| 1210 | r = find(g_pool, p); | 1228 | r = find(g_pool, p); |
| 1211 | if (r == NULL) { | 1229 | if (r == NULL) { |
| @@ -1245,6 +1263,7 @@ orealloc(void *p, size_t newsz) | |||
| 1245 | memset(q, SOME_JUNK, | 1263 | memset(q, SOME_JUNK, |
| 1246 | rnewsz - roldsz); | 1264 | rnewsz - roldsz); |
| 1247 | r->size = newsz; | 1265 | r->size = newsz; |
| 1266 | STATS_SETF(r, f); | ||
| 1248 | STATS_INC(g_pool->cheap_reallocs); | 1267 | STATS_INC(g_pool->cheap_reallocs); |
| 1249 | return p; | 1268 | return p; |
| 1250 | } else if (q != MAP_FAILED) | 1269 | } else if (q != MAP_FAILED) |
| @@ -1263,29 +1282,34 @@ orealloc(void *p, size_t newsz) | |||
| 1263 | } | 1282 | } |
| 1264 | unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz); | 1283 | unmap(g_pool, (char *)p + rnewsz, roldsz - rnewsz); |
| 1265 | r->size = gnewsz; | 1284 | r->size = gnewsz; |
| 1285 | STATS_SETF(r, f); | ||
| 1266 | return p; | 1286 | return p; |
| 1267 | } else { | 1287 | } else { |
| 1268 | if (newsz > oldsz && mopts.malloc_junk) | 1288 | if (newsz > oldsz && mopts.malloc_junk) |
| 1269 | memset((char *)p + newsz, SOME_JUNK, | 1289 | memset((char *)p + newsz, SOME_JUNK, |
| 1270 | rnewsz - mopts.malloc_guard - newsz); | 1290 | rnewsz - mopts.malloc_guard - newsz); |
| 1271 | r->size = gnewsz; | 1291 | r->size = gnewsz; |
| 1292 | STATS_SETF(r, f); | ||
| 1272 | return p; | 1293 | return p; |
| 1273 | } | 1294 | } |
| 1274 | } | 1295 | } |
| 1275 | if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) { | 1296 | if (newsz <= oldsz && newsz > oldsz / 2 && !mopts.malloc_realloc) { |
| 1276 | if (mopts.malloc_junk && newsz > 0) | 1297 | if (mopts.malloc_junk && newsz > 0) |
| 1277 | memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); | 1298 | memset((char *)p + newsz, SOME_JUNK, oldsz - newsz); |
| 1299 | STATS_SETF(r, f); | ||
| 1278 | return p; | 1300 | return p; |
| 1279 | } else if (newsz != oldsz || mopts.malloc_realloc) { | 1301 | } else if (newsz != oldsz || mopts.malloc_realloc) { |
| 1280 | q = omalloc(newsz, 0); | 1302 | q = omalloc(newsz, 0, f); |
| 1281 | if (q == NULL) | 1303 | if (q == NULL) |
| 1282 | return NULL; | 1304 | return NULL; |
| 1283 | if (newsz != 0 && oldsz != 0) | 1305 | if (newsz != 0 && oldsz != 0) |
| 1284 | memcpy(q, p, oldsz < newsz ? oldsz : newsz); | 1306 | memcpy(q, p, oldsz < newsz ? oldsz : newsz); |
| 1285 | ofree(p); | 1307 | ofree(p); |
| 1286 | return q; | 1308 | return q; |
| 1287 | } else | 1309 | } else { |
| 1310 | STATS_SETF(r, f); | ||
| 1288 | return p; | 1311 | return p; |
| 1312 | } | ||
| 1289 | } | 1313 | } |
| 1290 | 1314 | ||
| 1291 | void * | 1315 | void * |
| @@ -1304,7 +1328,7 @@ realloc(void *ptr, size_t size) | |||
| 1304 | malloc_recurse(); | 1328 | malloc_recurse(); |
| 1305 | return NULL; | 1329 | return NULL; |
| 1306 | } | 1330 | } |
| 1307 | r = orealloc(ptr, size); | 1331 | r = orealloc(ptr, size, CALLER); |
| 1308 | 1332 | ||
| 1309 | malloc_active--; | 1333 | malloc_active--; |
| 1310 | _MALLOC_UNLOCK(); | 1334 | _MALLOC_UNLOCK(); |
| @@ -1347,7 +1371,7 @@ calloc(size_t nmemb, size_t size) | |||
| 1347 | } | 1371 | } |
| 1348 | 1372 | ||
| 1349 | size *= nmemb; | 1373 | size *= nmemb; |
| 1350 | r = omalloc(size, 1); | 1374 | r = omalloc(size, 1, CALLER); |
| 1351 | 1375 | ||
| 1352 | malloc_active--; | 1376 | malloc_active--; |
| 1353 | _MALLOC_UNLOCK(); | 1377 | _MALLOC_UNLOCK(); |
| @@ -1386,17 +1410,110 @@ posix_memalign(void **memptr, size_t alignment, size_t size) | |||
| 1386 | } | 1410 | } |
| 1387 | 1411 | ||
| 1388 | #ifdef MALLOC_STATS | 1412 | #ifdef MALLOC_STATS |
| 1413 | |||
| 1414 | struct malloc_leak { | ||
| 1415 | void (*f)(); | ||
| 1416 | size_t total_size; | ||
| 1417 | int count; | ||
| 1418 | }; | ||
| 1419 | |||
| 1420 | struct leaknode { | ||
| 1421 | RB_ENTRY(leaknode) entry; | ||
| 1422 | struct malloc_leak d; | ||
| 1423 | }; | ||
| 1424 | |||
| 1425 | static int | ||
| 1426 | leakcmp(struct leaknode *e1, struct leaknode *e2) | ||
| 1427 | { | ||
| 1428 | return e1->d.f < e2->d.f ? -1 : e1->d.f > e2->d.f; | ||
| 1429 | } | ||
| 1430 | |||
| 1431 | static RB_HEAD(leaktree, leaknode) leakhead; | ||
| 1432 | RB_GENERATE_STATIC(leaktree, leaknode, entry, leakcmp) | ||
| 1433 | |||
| 1434 | static void | ||
| 1435 | putleakinfo(void *f, size_t sz, int cnt) | ||
| 1436 | { | ||
| 1437 | struct leaknode key, *p; | ||
| 1438 | static struct leaknode *page; | ||
| 1439 | static int used; | ||
| 1440 | |||
| 1441 | if (cnt == 0) | ||
| 1442 | return; | ||
| 1443 | |||
| 1444 | key.d.f = f; | ||
| 1445 | p = RB_FIND(leaktree, &leakhead, &key); | ||
| 1446 | if (p == NULL) { | ||
| 1447 | if (page == NULL || | ||
| 1448 | used >= MALLOC_PAGESIZE / sizeof(struct leaknode)) { | ||
| 1449 | page = MMAP(MALLOC_PAGESIZE); | ||
| 1450 | if (page == MAP_FAILED) | ||
| 1451 | return; | ||
| 1452 | used = 0; | ||
| 1453 | } | ||
| 1454 | p = &page[used++]; | ||
| 1455 | p->d.f = f; | ||
| 1456 | p->d.total_size = sz * cnt; | ||
| 1457 | p->d.count = cnt; | ||
| 1458 | RB_INSERT(leaktree, &leakhead, p); | ||
| 1459 | } else { | ||
| 1460 | p->d.total_size += sz * cnt; | ||
| 1461 | p->d.count += cnt; | ||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | static struct malloc_leak *malloc_leaks; | ||
| 1466 | |||
| 1467 | static void | ||
| 1468 | dump_leaks(int fd) | ||
| 1469 | { | ||
| 1470 | struct leaknode *p; | ||
| 1471 | char buf[64]; | ||
| 1472 | int i = 0; | ||
| 1473 | |||
| 1474 | snprintf(buf, sizeof(buf), "Leak report\n"); | ||
| 1475 | write(fd, buf, strlen(buf)); | ||
| 1476 | snprintf(buf, sizeof(buf), " f sum # avg\n"); | ||
| 1477 | write(fd, buf, strlen(buf)); | ||
| 1478 | /* XXX only one page of summary */ | ||
| 1479 | if (malloc_leaks == NULL) | ||
| 1480 | malloc_leaks = MMAP(MALLOC_PAGESIZE); | ||
| 1481 | if (malloc_leaks != MAP_FAILED) | ||
| 1482 | memset(malloc_leaks, 0, MALLOC_PAGESIZE); | ||
| 1483 | RB_FOREACH(p, leaktree, &leakhead) { | ||
| 1484 | snprintf(buf, sizeof(buf), "%12p %7zu %6u %6zu\n", p->d.f, | ||
| 1485 | p->d.total_size, p->d.count, p->d.total_size / p->d.count); | ||
| 1486 | write(fd, buf, strlen(buf)); | ||
| 1487 | if (malloc_leaks == MAP_FAILED || | ||
| 1488 | i >= MALLOC_PAGESIZE / sizeof(struct malloc_leak)) | ||
| 1489 | continue; | ||
| 1490 | malloc_leaks[i].f = p->d.f; | ||
| 1491 | malloc_leaks[i].total_size = p->d.total_size; | ||
| 1492 | malloc_leaks[i].count = p->d.count; | ||
| 1493 | i++; | ||
| 1494 | } | ||
| 1495 | } | ||
| 1496 | |||
| 1389 | static void | 1497 | static void |
| 1390 | dump_chunk(int fd, struct chunk_info *p, int fromfreelist) | 1498 | dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist) |
| 1391 | { | 1499 | { |
| 1392 | char buf[64]; | 1500 | char buf[64]; |
| 1393 | 1501 | ||
| 1394 | while (p != NULL) { | 1502 | while (p != NULL) { |
| 1395 | snprintf(buf, sizeof(buf), "chunk %d %d/%d %p\n", p->size, | 1503 | snprintf(buf, sizeof(buf), "chunk %12p %12p %4d %d/%d\n", |
| 1396 | p->free, p->total, p->page); | 1504 | p->page, ((p->bits[0] & 1) ? NULL : f), |
| 1505 | p->size, p->free, p->total); | ||
| 1397 | write(fd, buf, strlen(buf)); | 1506 | write(fd, buf, strlen(buf)); |
| 1398 | if (!fromfreelist) | 1507 | if (!fromfreelist) { |
| 1508 | if (p->bits[0] & 1) | ||
| 1509 | putleakinfo(NULL, p->size, p->total - p->free); | ||
| 1510 | else { | ||
| 1511 | putleakinfo(f, p->size, 1); | ||
| 1512 | putleakinfo(NULL, p->size, | ||
| 1513 | p->total - p->free - 1); | ||
| 1514 | } | ||
| 1399 | break; | 1515 | break; |
| 1516 | } | ||
| 1400 | p = LIST_NEXT(p, entries); | 1517 | p = LIST_NEXT(p, entries); |
| 1401 | if (p != NULL) { | 1518 | if (p != NULL) { |
| 1402 | snprintf(buf, sizeof(buf), " "); | 1519 | snprintf(buf, sizeof(buf), " "); |
| @@ -1418,7 +1535,7 @@ dump_free_chunk_info(int fd, struct dir_info *d) | |||
| 1418 | if (p != NULL) { | 1535 | if (p != NULL) { |
| 1419 | snprintf(buf, sizeof(buf), "%2d) ", i); | 1536 | snprintf(buf, sizeof(buf), "%2d) ", i); |
| 1420 | write(fd, buf, strlen(buf)); | 1537 | write(fd, buf, strlen(buf)); |
| 1421 | dump_chunk(fd, p, 1); | 1538 | dump_chunk(fd, p, NULL, 1); |
| 1422 | } | 1539 | } |
| 1423 | } | 1540 | } |
| 1424 | 1541 | ||
| @@ -1472,35 +1589,58 @@ malloc_dump1(int fd, struct dir_info *d) | |||
| 1472 | write(fd, buf, strlen(buf)); | 1589 | write(fd, buf, strlen(buf)); |
| 1473 | snprintf(buf, sizeof(buf), "Regions slots free %zu\n", d->regions_free); | 1590 | snprintf(buf, sizeof(buf), "Regions slots free %zu\n", d->regions_free); |
| 1474 | write(fd, buf, strlen(buf)); | 1591 | write(fd, buf, strlen(buf)); |
| 1592 | dump_free_chunk_info(fd, d); | ||
| 1593 | dump_free_page_info(fd, d); | ||
| 1594 | snprintf(buf, sizeof(buf), | ||
| 1595 | "slot) hash d type page f size [free/n]\n"); | ||
| 1596 | write(fd, buf, strlen(buf)); | ||
| 1475 | for (i = 0; i < d->regions_total; i++) { | 1597 | for (i = 0; i < d->regions_total; i++) { |
| 1476 | if (d->r[i].p != NULL) { | 1598 | if (d->r[i].p != NULL) { |
| 1477 | size_t h = hash(d->r[i].p) & | 1599 | size_t h = hash(d->r[i].p) & |
| 1478 | (d->regions_total - 1); | 1600 | (d->regions_total - 1); |
| 1479 | snprintf(buf, sizeof(buf), "%4zx) #%zx %zd ", | 1601 | snprintf(buf, sizeof(buf), "%4zx) #%4zx %zd ", |
| 1480 | i, h, h - i); | 1602 | i, h, h - i); |
| 1481 | write(fd, buf, strlen(buf)); | 1603 | write(fd, buf, strlen(buf)); |
| 1482 | REALSIZE(realsize, &d->r[i]); | 1604 | REALSIZE(realsize, &d->r[i]); |
| 1483 | if (realsize > MALLOC_MAXCHUNK) { | 1605 | if (realsize > MALLOC_MAXCHUNK) { |
| 1606 | putleakinfo(d->r[i].f, realsize, 1); | ||
| 1484 | snprintf(buf, sizeof(buf), | 1607 | snprintf(buf, sizeof(buf), |
| 1485 | "%p: %zu\n", d->r[i].p, realsize); | 1608 | "pages %12p %12p %zu\n", d->r[i].p, |
| 1609 | d->r[i].f, realsize); | ||
| 1486 | write(fd, buf, strlen(buf)); | 1610 | write(fd, buf, strlen(buf)); |
| 1487 | } else | 1611 | } else |
| 1488 | dump_chunk(fd, | 1612 | dump_chunk(fd, |
| 1489 | (struct chunk_info *)d->r[i].size, 0); | 1613 | (struct chunk_info *)d->r[i].size, |
| 1614 | d->r[i].f, 0); | ||
| 1490 | } | 1615 | } |
| 1491 | } | 1616 | } |
| 1492 | dump_free_chunk_info(fd, d); | ||
| 1493 | dump_free_page_info(fd, d); | ||
| 1494 | snprintf(buf, sizeof(buf), "In use %zu\n", malloc_used); | 1617 | snprintf(buf, sizeof(buf), "In use %zu\n", malloc_used); |
| 1495 | write(fd, buf, strlen(buf)); | 1618 | write(fd, buf, strlen(buf)); |
| 1496 | snprintf(buf, sizeof(buf), "Guarded %zu\n", malloc_guarded); | 1619 | snprintf(buf, sizeof(buf), "Guarded %zu\n", malloc_guarded); |
| 1497 | write(fd, buf, strlen(buf)); | 1620 | write(fd, buf, strlen(buf)); |
| 1621 | dump_leaks(fd); | ||
| 1622 | write(fd, "\n", 1); | ||
| 1498 | } | 1623 | } |
| 1499 | 1624 | ||
| 1500 | |||
| 1501 | void | 1625 | void |
| 1502 | malloc_dump(int fd) | 1626 | malloc_dump(int fd) |
| 1503 | { | 1627 | { |
| 1628 | int i; | ||
| 1629 | void *p; | ||
| 1630 | struct region_info *r; | ||
| 1631 | |||
| 1632 | for (i = 0; i <= MALLOC_DELAYED_CHUNKS; i++) { | ||
| 1633 | p = g_pool->delayed_chunks[i]; | ||
| 1634 | if (p == NULL) | ||
| 1635 | continue; | ||
| 1636 | r = find(g_pool, p); | ||
| 1637 | if (r == NULL) | ||
| 1638 | wrterror("bogus pointer in malloc_dump", p); | ||
| 1639 | free_bytes(g_pool, r, p); | ||
| 1640 | g_pool->delayed_chunks[i] = NULL; | ||
| 1641 | } | ||
| 1642 | /* XXX leak when run multiple times */ | ||
| 1643 | RB_INIT(&leakhead); | ||
| 1504 | malloc_dump1(fd, g_pool); | 1644 | malloc_dump1(fd, g_pool); |
| 1505 | } | 1645 | } |
| 1506 | 1646 | ||
