diff options
Diffstat (limited to '')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 118 |
1 files changed, 36 insertions, 82 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 221a876f69..0c22398841 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.232 2017/09/23 15:13:12 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.233 2017/10/05 04:41:43 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> |
| @@ -273,24 +273,15 @@ struct dir_info *getpool(void) | |||
| 273 | static __dead void | 273 | static __dead void |
| 274 | wrterror(struct dir_info *d, char *msg, ...) | 274 | wrterror(struct dir_info *d, char *msg, ...) |
| 275 | { | 275 | { |
| 276 | struct iovec iov[3]; | ||
| 277 | char pidbuf[80]; | ||
| 278 | char buf[80]; | ||
| 279 | int saved_errno = errno; | 276 | int saved_errno = errno; |
| 280 | va_list ap; | 277 | va_list ap; |
| 281 | 278 | ||
| 282 | iov[0].iov_base = pidbuf; | 279 | dprintf(STDERR_FILENO, "%s(%d) in %s(): ", __progname, |
| 283 | snprintf(pidbuf, sizeof(pidbuf), "%s(%d) in %s(): ", __progname, | ||
| 284 | getpid(), (d != NULL && d->func) ? d->func : "unknown"); | 280 | getpid(), (d != NULL && d->func) ? d->func : "unknown"); |
| 285 | iov[0].iov_len = strlen(pidbuf); | ||
| 286 | iov[1].iov_base = buf; | ||
| 287 | va_start(ap, msg); | 281 | va_start(ap, msg); |
| 288 | vsnprintf(buf, sizeof(buf), msg, ap); | 282 | vdprintf(STDERR_FILENO, msg, ap); |
| 289 | va_end(ap); | 283 | va_end(ap); |
| 290 | iov[1].iov_len = strlen(buf); | 284 | dprintf(STDERR_FILENO, "\n"); |
| 291 | iov[2].iov_base = "\n"; | ||
| 292 | iov[2].iov_len = 1; | ||
| 293 | writev(STDERR_FILENO, iov, 3); | ||
| 294 | 285 | ||
| 295 | #ifdef MALLOC_STATS | 286 | #ifdef MALLOC_STATS |
| 296 | if (mopts.malloc_stats) | 287 | if (mopts.malloc_stats) |
| @@ -560,9 +551,8 @@ omalloc_parseopt(char opt) | |||
| 560 | mopts.malloc_xmalloc = 1; | 551 | mopts.malloc_xmalloc = 1; |
| 561 | break; | 552 | break; |
| 562 | default: { | 553 | default: { |
| 563 | static const char q[] = "malloc() warning: " | 554 | dprintf(STDERR_FILENO, "malloc() warning: " |
| 564 | "unknown char in MALLOC_OPTIONS\n"; | 555 | "unknown char in MALLOC_OPTIONS\n"); |
| 565 | write(STDERR_FILENO, q, sizeof(q) - 1); | ||
| 566 | break; | 556 | break; |
| 567 | } | 557 | } |
| 568 | } | 558 | } |
| @@ -623,9 +613,8 @@ omalloc_init(void) | |||
| 623 | 613 | ||
| 624 | #ifdef MALLOC_STATS | 614 | #ifdef MALLOC_STATS |
| 625 | if (mopts.malloc_stats && (atexit(malloc_exit) == -1)) { | 615 | if (mopts.malloc_stats && (atexit(malloc_exit) == -1)) { |
| 626 | static const char q[] = "malloc() warning: atexit(2) failed." | 616 | dprintf(STDERR_FILENO, "malloc() warning: atexit(2) failed." |
| 627 | " Will not be able to dump stats on exit\n"; | 617 | " Will not be able to dump stats on exit\n"); |
| 628 | write(STDERR_FILENO, q, sizeof(q) - 1); | ||
| 629 | } | 618 | } |
| 630 | #endif /* MALLOC_STATS */ | 619 | #endif /* MALLOC_STATS */ |
| 631 | 620 | ||
| @@ -2135,29 +2124,21 @@ putleakinfo(void *f, size_t sz, int cnt) | |||
| 2135 | static struct malloc_leak *malloc_leaks; | 2124 | static struct malloc_leak *malloc_leaks; |
| 2136 | 2125 | ||
| 2137 | static void | 2126 | static void |
| 2138 | writestr(int fd, const char *p) | ||
| 2139 | { | ||
| 2140 | write(fd, p, strlen(p)); | ||
| 2141 | } | ||
| 2142 | |||
| 2143 | static void | ||
| 2144 | dump_leaks(int fd) | 2127 | dump_leaks(int fd) |
| 2145 | { | 2128 | { |
| 2146 | struct leaknode *p; | 2129 | struct leaknode *p; |
| 2147 | char buf[64]; | ||
| 2148 | int i = 0; | 2130 | int i = 0; |
| 2149 | 2131 | ||
| 2150 | writestr(fd, "Leak report\n"); | 2132 | dprintf(fd, "Leak report\n"); |
| 2151 | writestr(fd, " f sum # avg\n"); | 2133 | dprintf(fd, " f sum # avg\n"); |
| 2152 | /* XXX only one page of summary */ | 2134 | /* XXX only one page of summary */ |
| 2153 | if (malloc_leaks == NULL) | 2135 | if (malloc_leaks == NULL) |
| 2154 | malloc_leaks = MMAP(MALLOC_PAGESIZE); | 2136 | malloc_leaks = MMAP(MALLOC_PAGESIZE); |
| 2155 | if (malloc_leaks != MAP_FAILED) | 2137 | if (malloc_leaks != MAP_FAILED) |
| 2156 | memset(malloc_leaks, 0, MALLOC_PAGESIZE); | 2138 | memset(malloc_leaks, 0, MALLOC_PAGESIZE); |
| 2157 | RBT_FOREACH(p, leaktree, &leakhead) { | 2139 | RBT_FOREACH(p, leaktree, &leakhead) { |
| 2158 | snprintf(buf, sizeof(buf), "%18p %7zu %6u %6zu\n", p->d.f, | 2140 | dprintf(fd, "%18p %7zu %6u %6zu\n", p->d.f, |
| 2159 | p->d.total_size, p->d.count, p->d.total_size / p->d.count); | 2141 | p->d.total_size, p->d.count, p->d.total_size / p->d.count); |
| 2160 | write(fd, buf, strlen(buf)); | ||
| 2161 | if (malloc_leaks == MAP_FAILED || | 2142 | if (malloc_leaks == MAP_FAILED || |
| 2162 | i >= MALLOC_PAGESIZE / sizeof(struct malloc_leak)) | 2143 | i >= MALLOC_PAGESIZE / sizeof(struct malloc_leak)) |
| 2163 | continue; | 2144 | continue; |
| @@ -2171,13 +2152,10 @@ dump_leaks(int fd) | |||
| 2171 | static void | 2152 | static void |
| 2172 | dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist) | 2153 | dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist) |
| 2173 | { | 2154 | { |
| 2174 | char buf[64]; | ||
| 2175 | |||
| 2176 | while (p != NULL) { | 2155 | while (p != NULL) { |
| 2177 | snprintf(buf, sizeof(buf), "chunk %18p %18p %4d %d/%d\n", | 2156 | dprintf(fd, "chunk %18p %18p %4d %d/%d\n", |
| 2178 | p->page, ((p->bits[0] & 1) ? NULL : f), | 2157 | p->page, ((p->bits[0] & 1) ? NULL : f), |
| 2179 | p->size, p->free, p->total); | 2158 | p->size, p->free, p->total); |
| 2180 | write(fd, buf, strlen(buf)); | ||
| 2181 | if (!fromfreelist) { | 2159 | if (!fromfreelist) { |
| 2182 | if (p->bits[0] & 1) | 2160 | if (p->bits[0] & 1) |
| 2183 | putleakinfo(NULL, p->size, p->total - p->free); | 2161 | putleakinfo(NULL, p->size, p->total - p->free); |
| @@ -2190,18 +2168,17 @@ dump_chunk(int fd, struct chunk_info *p, void *f, int fromfreelist) | |||
| 2190 | } | 2168 | } |
| 2191 | p = LIST_NEXT(p, entries); | 2169 | p = LIST_NEXT(p, entries); |
| 2192 | if (p != NULL) | 2170 | if (p != NULL) |
| 2193 | writestr(fd, " "); | 2171 | dprintf(fd, " "); |
| 2194 | } | 2172 | } |
| 2195 | } | 2173 | } |
| 2196 | 2174 | ||
| 2197 | static void | 2175 | static void |
| 2198 | dump_free_chunk_info(int fd, struct dir_info *d) | 2176 | dump_free_chunk_info(int fd, struct dir_info *d) |
| 2199 | { | 2177 | { |
| 2200 | char buf[64]; | ||
| 2201 | int i, j, count; | 2178 | int i, j, count; |
| 2202 | struct chunk_info *p; | 2179 | struct chunk_info *p; |
| 2203 | 2180 | ||
| 2204 | writestr(fd, "Free chunk structs:\n"); | 2181 | dprintf(fd, "Free chunk structs:\n"); |
| 2205 | for (i = 0; i <= MALLOC_MAXSHIFT; i++) { | 2182 | for (i = 0; i <= MALLOC_MAXSHIFT; i++) { |
| 2206 | count = 0; | 2183 | count = 0; |
| 2207 | LIST_FOREACH(p, &d->chunk_info_list[i], entries) | 2184 | LIST_FOREACH(p, &d->chunk_info_list[i], entries) |
| @@ -2210,12 +2187,11 @@ dump_free_chunk_info(int fd, struct dir_info *d) | |||
| 2210 | p = LIST_FIRST(&d->chunk_dir[i][j]); | 2187 | p = LIST_FIRST(&d->chunk_dir[i][j]); |
| 2211 | if (p == NULL && count == 0) | 2188 | if (p == NULL && count == 0) |
| 2212 | continue; | 2189 | continue; |
| 2213 | snprintf(buf, sizeof(buf), "%2d) %3d ", i, count); | 2190 | dprintf(fd, "%2d) %3d ", i, count); |
| 2214 | write(fd, buf, strlen(buf)); | ||
| 2215 | if (p != NULL) | 2191 | if (p != NULL) |
| 2216 | dump_chunk(fd, p, NULL, 1); | 2192 | dump_chunk(fd, p, NULL, 1); |
| 2217 | else | 2193 | else |
| 2218 | write(fd, "\n", 1); | 2194 | dprintf(fd, "\n"); |
| 2219 | } | 2195 | } |
| 2220 | } | 2196 | } |
| 2221 | 2197 | ||
| @@ -2224,19 +2200,14 @@ dump_free_chunk_info(int fd, struct dir_info *d) | |||
| 2224 | static void | 2200 | static void |
| 2225 | dump_free_page_info(int fd, struct dir_info *d) | 2201 | dump_free_page_info(int fd, struct dir_info *d) |
| 2226 | { | 2202 | { |
| 2227 | char buf[64]; | ||
| 2228 | int i; | 2203 | int i; |
| 2229 | 2204 | ||
| 2230 | snprintf(buf, sizeof(buf), "Free pages cached: %zu\n", | 2205 | dprintf(fd, "Free pages cached: %zu\n", d->free_regions_size); |
| 2231 | d->free_regions_size); | ||
| 2232 | write(fd, buf, strlen(buf)); | ||
| 2233 | for (i = 0; i < mopts.malloc_cache; i++) { | 2206 | for (i = 0; i < mopts.malloc_cache; i++) { |
| 2234 | if (d->free_regions[i].p != NULL) { | 2207 | if (d->free_regions[i].p != NULL) { |
| 2235 | snprintf(buf, sizeof(buf), "%2d) ", i); | 2208 | dprintf(fd, "%2d) ", i); |
| 2236 | write(fd, buf, strlen(buf)); | 2209 | dprintf(fd, "free at %p: %zu\n", |
| 2237 | snprintf(buf, sizeof(buf), "free at %p: %zu\n", | ||
| 2238 | d->free_regions[i].p, d->free_regions[i].size); | 2210 | d->free_regions[i].p, d->free_regions[i].size); |
| 2239 | write(fd, buf, strlen(buf)); | ||
| 2240 | } | 2211 | } |
| 2241 | } | 2212 | } |
| 2242 | } | 2213 | } |
| @@ -2244,50 +2215,39 @@ dump_free_page_info(int fd, struct dir_info *d) | |||
| 2244 | static void | 2215 | static void |
| 2245 | malloc_dump1(int fd, int poolno, struct dir_info *d) | 2216 | malloc_dump1(int fd, int poolno, struct dir_info *d) |
| 2246 | { | 2217 | { |
| 2247 | char buf[100]; | ||
| 2248 | size_t i, realsize; | 2218 | size_t i, realsize; |
| 2249 | 2219 | ||
| 2250 | snprintf(buf, sizeof(buf), "Malloc dir of %s pool %d at %p\n", __progname, poolno, d); | 2220 | dprintf(fd, "Malloc dir of %s pool %d at %p\n", __progname, poolno, d); |
| 2251 | write(fd, buf, strlen(buf)); | ||
| 2252 | if (d == NULL) | 2221 | if (d == NULL) |
| 2253 | return; | 2222 | return; |
| 2254 | snprintf(buf, sizeof(buf), "Region slots free %zu/%zu\n", | 2223 | dprintf(fd, "Region slots free %zu/%zu\n", |
| 2255 | d->regions_free, d->regions_total); | 2224 | d->regions_free, d->regions_total); |
| 2256 | write(fd, buf, strlen(buf)); | 2225 | dprintf(fd, "Finds %zu/%zu\n", d->finds, |
| 2257 | snprintf(buf, sizeof(buf), "Finds %zu/%zu\n", d->finds, | ||
| 2258 | d->find_collisions); | 2226 | d->find_collisions); |
| 2259 | write(fd, buf, strlen(buf)); | 2227 | dprintf(fd, "Inserts %zu/%zu\n", d->inserts, |
| 2260 | snprintf(buf, sizeof(buf), "Inserts %zu/%zu\n", d->inserts, | ||
| 2261 | d->insert_collisions); | 2228 | d->insert_collisions); |
| 2262 | write(fd, buf, strlen(buf)); | 2229 | dprintf(fd, "Deletes %zu/%zu\n", d->deletes, |
| 2263 | snprintf(buf, sizeof(buf), "Deletes %zu/%zu\n", d->deletes, | ||
| 2264 | d->delete_moves); | 2230 | d->delete_moves); |
| 2265 | write(fd, buf, strlen(buf)); | 2231 | dprintf(fd, "Cheap reallocs %zu/%zu\n", |
| 2266 | snprintf(buf, sizeof(buf), "Cheap reallocs %zu/%zu\n", | ||
| 2267 | d->cheap_reallocs, d->cheap_realloc_tries); | 2232 | d->cheap_reallocs, d->cheap_realloc_tries); |
| 2268 | write(fd, buf, strlen(buf)); | 2233 | dprintf(fd, "In use %zu\n", d->malloc_used); |
| 2269 | snprintf(buf, sizeof(buf), "In use %zu\n", d->malloc_used); | 2234 | dprintf(fd, "Guarded %zu\n", d->malloc_guarded); |
| 2270 | write(fd, buf, strlen(buf)); | ||
| 2271 | snprintf(buf, sizeof(buf), "Guarded %zu\n", d->malloc_guarded); | ||
| 2272 | write(fd, buf, strlen(buf)); | ||
| 2273 | dump_free_chunk_info(fd, d); | 2235 | dump_free_chunk_info(fd, d); |
| 2274 | dump_free_page_info(fd, d); | 2236 | dump_free_page_info(fd, d); |
| 2275 | writestr(fd, | 2237 | dprintf(fd, |
| 2276 | "slot) hash d type page f size [free/n]\n"); | 2238 | "slot) hash d type page f size [free/n]\n"); |
| 2277 | for (i = 0; i < d->regions_total; i++) { | 2239 | for (i = 0; i < d->regions_total; i++) { |
| 2278 | if (d->r[i].p != NULL) { | 2240 | if (d->r[i].p != NULL) { |
| 2279 | size_t h = hash(d->r[i].p) & | 2241 | size_t h = hash(d->r[i].p) & |
| 2280 | (d->regions_total - 1); | 2242 | (d->regions_total - 1); |
| 2281 | snprintf(buf, sizeof(buf), "%4zx) #%4zx %zd ", | 2243 | dprintf(fd, "%4zx) #%4zx %zd ", |
| 2282 | i, h, h - i); | 2244 | i, h, h - i); |
| 2283 | write(fd, buf, strlen(buf)); | ||
| 2284 | REALSIZE(realsize, &d->r[i]); | 2245 | REALSIZE(realsize, &d->r[i]); |
| 2285 | if (realsize > MALLOC_MAXCHUNK) { | 2246 | if (realsize > MALLOC_MAXCHUNK) { |
| 2286 | putleakinfo(d->r[i].f, realsize, 1); | 2247 | putleakinfo(d->r[i].f, realsize, 1); |
| 2287 | snprintf(buf, sizeof(buf), | 2248 | dprintf(fd, |
| 2288 | "pages %18p %18p %zu\n", d->r[i].p, | 2249 | "pages %18p %18p %zu\n", d->r[i].p, |
| 2289 | d->r[i].f, realsize); | 2250 | d->r[i].f, realsize); |
| 2290 | write(fd, buf, strlen(buf)); | ||
| 2291 | } else | 2251 | } else |
| 2292 | dump_chunk(fd, | 2252 | dump_chunk(fd, |
| 2293 | (struct chunk_info *)d->r[i].size, | 2253 | (struct chunk_info *)d->r[i].size, |
| @@ -2295,7 +2255,7 @@ malloc_dump1(int fd, int poolno, struct dir_info *d) | |||
| 2295 | } | 2255 | } |
| 2296 | } | 2256 | } |
| 2297 | dump_leaks(fd); | 2257 | dump_leaks(fd); |
| 2298 | write(fd, "\n", 1); | 2258 | dprintf(fd, "\n"); |
| 2299 | } | 2259 | } |
| 2300 | 2260 | ||
| 2301 | void | 2261 | void |
| @@ -2341,16 +2301,12 @@ DEF_WEAK(malloc_gdump); | |||
| 2341 | static void | 2301 | static void |
| 2342 | malloc_exit(void) | 2302 | malloc_exit(void) |
| 2343 | { | 2303 | { |
| 2344 | static const char q[] = "malloc() warning: Couldn't dump stats\n"; | ||
| 2345 | int save_errno = errno, fd, i; | 2304 | int save_errno = errno, fd, i; |
| 2346 | char buf[100]; | ||
| 2347 | 2305 | ||
| 2348 | fd = open("malloc.out", O_RDWR|O_APPEND); | 2306 | fd = open("malloc.out", O_RDWR|O_APPEND); |
| 2349 | if (fd != -1) { | 2307 | if (fd != -1) { |
| 2350 | snprintf(buf, sizeof(buf), "******** Start dump %s *******\n", | 2308 | dprintf(fd, "******** Start dump %s *******\n", __progname); |
| 2351 | __progname); | 2309 | dprintf(fd, |
| 2352 | write(fd, buf, strlen(buf)); | ||
| 2353 | snprintf(buf, sizeof(buf), | ||
| 2354 | "MT=%d I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", | 2310 | "MT=%d I=%d F=%d U=%d J=%d R=%d X=%d C=%d cache=%u G=%zu\n", |
| 2355 | mopts.malloc_mt, mopts.internal_funcs, | 2311 | mopts.malloc_mt, mopts.internal_funcs, |
| 2356 | mopts.malloc_freecheck, | 2312 | mopts.malloc_freecheck, |
| @@ -2358,16 +2314,14 @@ malloc_exit(void) | |||
| 2358 | mopts.malloc_realloc, mopts.malloc_xmalloc, | 2314 | mopts.malloc_realloc, mopts.malloc_xmalloc, |
| 2359 | mopts.chunk_canaries, mopts.malloc_cache, | 2315 | mopts.chunk_canaries, mopts.malloc_cache, |
| 2360 | mopts.malloc_guard); | 2316 | mopts.malloc_guard); |
| 2361 | write(fd, buf, strlen(buf)); | ||
| 2362 | 2317 | ||
| 2363 | for (i = 0; i < _MALLOC_MUTEXES; i++) | 2318 | for (i = 0; i < _MALLOC_MUTEXES; i++) |
| 2364 | malloc_dump(fd, i, mopts.malloc_pool[i]); | 2319 | malloc_dump(fd, i, mopts.malloc_pool[i]); |
| 2365 | snprintf(buf, sizeof(buf), "******** End dump %s *******\n", | 2320 | dprintf(fd, "******** End dump %s *******\n", __progname); |
| 2366 | __progname); | ||
| 2367 | write(fd, buf, strlen(buf)); | ||
| 2368 | close(fd); | 2321 | close(fd); |
| 2369 | } else | 2322 | } else |
| 2370 | write(STDERR_FILENO, q, sizeof(q) - 1); | 2323 | dprintf(STDERR_FILENO, |
| 2324 | "malloc() warning: Couldn't dump stats\n"); | ||
| 2371 | errno = save_errno; | 2325 | errno = save_errno; |
| 2372 | } | 2326 | } |
| 2373 | 2327 | ||
