diff options
Diffstat (limited to 'src/lib/libc')
| -rw-r--r-- | src/lib/libc/stdlib/malloc.c | 215 |
1 files changed, 112 insertions, 103 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index 24610db9c5..2b51f61f38 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.204 2016/10/20 11:29:34 otto Exp $ */ | 1 | /* $OpenBSD: malloc.c,v 1.205 2016/10/21 06:55:09 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> |
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <sys/mman.h> | 31 | #include <sys/mman.h> |
| 32 | #include <sys/uio.h> | 32 | #include <sys/uio.h> |
| 33 | #include <errno.h> | 33 | #include <errno.h> |
| 34 | #include <stdarg.h> | ||
| 34 | #include <stdint.h> | 35 | #include <stdint.h> |
| 35 | #include <stdlib.h> | 36 | #include <stdlib.h> |
| 36 | #include <string.h> | 37 | #include <string.h> |
| @@ -199,6 +200,8 @@ static union { | |||
| 199 | char *malloc_options; /* compile-time options */ | 200 | char *malloc_options; /* compile-time options */ |
| 200 | 201 | ||
| 201 | static u_char getrbyte(struct dir_info *d); | 202 | static u_char getrbyte(struct dir_info *d); |
| 203 | static __dead void wrterror(struct dir_info *d, char *msg, ...) | ||
| 204 | __attribute__((__format__ (printf, 2, 3))); | ||
| 202 | 205 | ||
| 203 | #ifdef MALLOC_STATS | 206 | #ifdef MALLOC_STATS |
| 204 | void malloc_dump(int, struct dir_info *); | 207 | void malloc_dump(int, struct dir_info *); |
| @@ -261,40 +264,26 @@ struct dir_info *getpool(void) | |||
| 261 | } | 264 | } |
| 262 | 265 | ||
| 263 | static __dead void | 266 | static __dead void |
| 264 | wrterror(struct dir_info *d, char *msg, void *p) | 267 | wrterror(struct dir_info *d, char *msg, ...) |
| 265 | { | 268 | { |
| 266 | char *q = " error: "; | 269 | struct iovec iov[3]; |
| 267 | struct iovec iov[7]; | 270 | char pidbuf[80]; |
| 268 | char pidbuf[20]; | 271 | char buf[80]; |
| 269 | char buf[20]; | 272 | int saved_errno = errno; |
| 270 | int saved_errno = errno, i; | 273 | va_list ap; |
| 271 | 274 | ||
| 272 | iov[0].iov_base = __progname; | 275 | iov[0].iov_base = pidbuf; |
| 273 | iov[0].iov_len = strlen(__progname); | 276 | snprintf(pidbuf, sizeof(pidbuf), "%s(%d) in %s(): ", __progname, |
| 274 | iov[1].iov_base = pidbuf; | 277 | getpid(), d->func ? d->func : "unknown"); |
| 275 | snprintf(pidbuf, sizeof(pidbuf), "(%d) in ", getpid()); | 278 | iov[0].iov_len = strlen(pidbuf); |
| 276 | iov[1].iov_len = strlen(pidbuf); | 279 | iov[1].iov_base = buf; |
| 277 | if (d != NULL) { | 280 | va_start(ap, msg); |
| 278 | iov[2].iov_base = d->func; | 281 | vsnprintf(buf, sizeof(buf), msg, ap); |
| 279 | iov[2].iov_len = strlen(d->func); | 282 | va_end(ap); |
| 280 | } else { | 283 | iov[1].iov_len = strlen(buf); |
| 281 | iov[2].iov_base = "unknown"; | 284 | iov[2].iov_base = "\n"; |
| 282 | iov[2].iov_len = 7; | 285 | iov[2].iov_len = 1; |
| 283 | } | 286 | writev(STDERR_FILENO, iov, 3); |
| 284 | iov[3].iov_base = q; | ||
| 285 | iov[3].iov_len = strlen(q); | ||
| 286 | iov[4].iov_base = msg; | ||
| 287 | iov[4].iov_len = strlen(msg); | ||
| 288 | iov[5].iov_base = buf; | ||
| 289 | if (p == NULL) | ||
| 290 | iov[5].iov_len = 0; | ||
| 291 | else { | ||
| 292 | snprintf(buf, sizeof(buf), " %010p", p); | ||
| 293 | iov[5].iov_len = strlen(buf); | ||
| 294 | } | ||
| 295 | iov[6].iov_base = "\n"; | ||
| 296 | iov[6].iov_len = 1; | ||
| 297 | writev(STDERR_FILENO, iov, 7); | ||
| 298 | 287 | ||
| 299 | #ifdef MALLOC_STATS | 288 | #ifdef MALLOC_STATS |
| 300 | if (mopts.malloc_stats) | 289 | if (mopts.malloc_stats) |
| @@ -342,12 +331,12 @@ unmap(struct dir_info *d, void *p, size_t sz) | |||
| 342 | u_int i, offset; | 331 | u_int i, offset; |
| 343 | 332 | ||
| 344 | if (sz != PAGEROUND(sz)) | 333 | if (sz != PAGEROUND(sz)) |
| 345 | wrterror(d, "munmap round", NULL); | 334 | wrterror(d, "munmap round"); |
| 346 | 335 | ||
| 347 | if (psz > mopts.malloc_cache) { | 336 | if (psz > mopts.malloc_cache) { |
| 348 | i = munmap(p, sz); | 337 | i = munmap(p, sz); |
| 349 | if (i) | 338 | if (i) |
| 350 | wrterror(d, "munmap", p); | 339 | wrterror(d, "munmap %p", p); |
| 351 | STATS_SUB(d->malloc_used, sz); | 340 | STATS_SUB(d->malloc_used, sz); |
| 352 | return; | 341 | return; |
| 353 | } | 342 | } |
| @@ -361,7 +350,7 @@ unmap(struct dir_info *d, void *p, size_t sz) | |||
| 361 | if (r->p != NULL) { | 350 | if (r->p != NULL) { |
| 362 | rsz = r->size << MALLOC_PAGESHIFT; | 351 | rsz = r->size << MALLOC_PAGESHIFT; |
| 363 | if (munmap(r->p, rsz)) | 352 | if (munmap(r->p, rsz)) |
| 364 | wrterror(d, "munmap", r->p); | 353 | wrterror(d, "munmap %p", r->p); |
| 365 | r->p = NULL; | 354 | r->p = NULL; |
| 366 | if (tounmap > r->size) | 355 | if (tounmap > r->size) |
| 367 | tounmap -= r->size; | 356 | tounmap -= r->size; |
| @@ -373,7 +362,7 @@ unmap(struct dir_info *d, void *p, size_t sz) | |||
| 373 | } | 362 | } |
| 374 | } | 363 | } |
| 375 | if (tounmap > 0) | 364 | if (tounmap > 0) |
| 376 | wrterror(d, "malloc cache underflow", NULL); | 365 | wrterror(d, "malloc cache underflow"); |
| 377 | for (i = 0; i < mopts.malloc_cache; i++) { | 366 | for (i = 0; i < mopts.malloc_cache; i++) { |
| 378 | r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)]; | 367 | r = &d->free_regions[(i + offset) & (mopts.malloc_cache - 1)]; |
| 379 | if (r->p == NULL) { | 368 | if (r->p == NULL) { |
| @@ -393,9 +382,9 @@ unmap(struct dir_info *d, void *p, size_t sz) | |||
| 393 | } | 382 | } |
| 394 | } | 383 | } |
| 395 | if (i == mopts.malloc_cache) | 384 | if (i == mopts.malloc_cache) |
| 396 | wrterror(d, "malloc free slot lost", NULL); | 385 | wrterror(d, "malloc free slot lost"); |
| 397 | if (d->free_regions_size > mopts.malloc_cache) | 386 | if (d->free_regions_size > mopts.malloc_cache) |
| 398 | wrterror(d, "malloc cache overflow", NULL); | 387 | wrterror(d, "malloc cache overflow"); |
| 399 | } | 388 | } |
| 400 | 389 | ||
| 401 | static void | 390 | static void |
| @@ -410,7 +399,7 @@ zapcacheregion(struct dir_info *d, void *p, size_t len) | |||
| 410 | if (r->p >= p && r->p <= (void *)((char *)p + len)) { | 399 | if (r->p >= p && r->p <= (void *)((char *)p + len)) { |
| 411 | rsz = r->size << MALLOC_PAGESHIFT; | 400 | rsz = r->size << MALLOC_PAGESHIFT; |
| 412 | if (munmap(r->p, rsz)) | 401 | if (munmap(r->p, rsz)) |
| 413 | wrterror(d, "munmap", r->p); | 402 | wrterror(d, "munmap %p", r->p); |
| 414 | r->p = NULL; | 403 | r->p = NULL; |
| 415 | d->free_regions_size -= r->size; | 404 | d->free_regions_size -= r->size; |
| 416 | r->size = 0; | 405 | r->size = 0; |
| @@ -429,9 +418,9 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) | |||
| 429 | 418 | ||
| 430 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || | 419 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || |
| 431 | d->canary1 != ~d->canary2) | 420 | d->canary1 != ~d->canary2) |
| 432 | wrterror(d, "internal struct corrupt", NULL); | 421 | wrterror(d, "internal struct corrupt"); |
| 433 | if (sz != PAGEROUND(sz)) | 422 | if (sz != PAGEROUND(sz)) |
| 434 | wrterror(d, "map round", NULL); | 423 | wrterror(d, "map round"); |
| 435 | 424 | ||
| 436 | if (!hint && psz > d->free_regions_size) { | 425 | if (!hint && psz > d->free_regions_size) { |
| 437 | _MALLOC_LEAVE(d); | 426 | _MALLOC_LEAVE(d); |
| @@ -486,7 +475,7 @@ map(struct dir_info *d, void *hint, size_t sz, int zero_fill) | |||
| 486 | if (hint) | 475 | if (hint) |
| 487 | return MAP_FAILED; | 476 | return MAP_FAILED; |
| 488 | if (d->free_regions_size > mopts.malloc_cache) | 477 | if (d->free_regions_size > mopts.malloc_cache) |
| 489 | wrterror(d, "malloc cache", NULL); | 478 | wrterror(d, "malloc cache"); |
| 490 | _MALLOC_LEAVE(d); | 479 | _MALLOC_LEAVE(d); |
| 491 | p = MMAP(sz); | 480 | p = MMAP(sz); |
| 492 | _MALLOC_ENTER(d); | 481 | _MALLOC_ENTER(d); |
| @@ -673,7 +662,7 @@ omalloc_poolinit(struct dir_info **dp) | |||
| 673 | * lies (subject to alignment by 1 << MALLOC_MINSHIFT) | 662 | * lies (subject to alignment by 1 << MALLOC_MINSHIFT) |
| 674 | */ | 663 | */ |
| 675 | if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED) | 664 | if ((p = MMAP(DIR_INFO_RSZ + (MALLOC_PAGESIZE * 2))) == MAP_FAILED) |
| 676 | wrterror(NULL, "malloc init mmap failed", NULL); | 665 | wrterror(NULL, "malloc init mmap failed"); |
| 677 | mprotect(p, MALLOC_PAGESIZE, PROT_NONE); | 666 | mprotect(p, MALLOC_PAGESIZE, PROT_NONE); |
| 678 | mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ, | 667 | mprotect(p + MALLOC_PAGESIZE + DIR_INFO_RSZ, |
| 679 | MALLOC_PAGESIZE, PROT_NONE); | 668 | MALLOC_PAGESIZE, PROT_NONE); |
| @@ -687,7 +676,7 @@ omalloc_poolinit(struct dir_info **dp) | |||
| 687 | d->r = MMAP(regioninfo_size); | 676 | d->r = MMAP(regioninfo_size); |
| 688 | if (d->r == MAP_FAILED) { | 677 | if (d->r == MAP_FAILED) { |
| 689 | d->regions_total = 0; | 678 | d->regions_total = 0; |
| 690 | wrterror(NULL, "malloc init mmap failed", NULL); | 679 | wrterror(NULL, "malloc init mmap failed"); |
| 691 | } | 680 | } |
| 692 | for (i = 0; i <= MALLOC_MAXSHIFT; i++) { | 681 | for (i = 0; i <= MALLOC_MAXSHIFT; i++) { |
| 693 | LIST_INIT(&d->chunk_info_list[i]); | 682 | LIST_INIT(&d->chunk_info_list[i]); |
| @@ -738,7 +727,7 @@ omalloc_grow(struct dir_info *d) | |||
| 738 | } | 727 | } |
| 739 | /* avoid pages containing meta info to end up in cache */ | 728 | /* avoid pages containing meta info to end up in cache */ |
| 740 | if (munmap(d->r, d->regions_total * sizeof(struct region_info))) | 729 | if (munmap(d->r, d->regions_total * sizeof(struct region_info))) |
| 741 | wrterror(d, "munmap", d->r); | 730 | wrterror(d, "munmap %p", d->r); |
| 742 | else | 731 | else |
| 743 | STATS_SUB(d->malloc_used, | 732 | STATS_SUB(d->malloc_used, |
| 744 | d->regions_total * sizeof(struct region_info)); | 733 | d->regions_total * sizeof(struct region_info)); |
| @@ -828,7 +817,7 @@ find(struct dir_info *d, void *p) | |||
| 828 | 817 | ||
| 829 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || | 818 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || |
| 830 | d->canary1 != ~d->canary2) | 819 | d->canary1 != ~d->canary2) |
| 831 | wrterror(d, "internal struct corrupt", NULL); | 820 | wrterror(d, "internal struct corrupt"); |
| 832 | p = MASK_POINTER(p); | 821 | p = MASK_POINTER(p); |
| 833 | index = hash(p) & mask; | 822 | index = hash(p) & mask; |
| 834 | r = d->r[index].p; | 823 | r = d->r[index].p; |
| @@ -851,7 +840,7 @@ delete(struct dir_info *d, struct region_info *ri) | |||
| 851 | size_t i, j, r; | 840 | size_t i, j, r; |
| 852 | 841 | ||
| 853 | if (d->regions_total & (d->regions_total - 1)) | 842 | if (d->regions_total & (d->regions_total - 1)) |
| 854 | wrterror(d, "regions_total not 2^x", NULL); | 843 | wrterror(d, "regions_total not 2^x"); |
| 855 | d->regions_free++; | 844 | d->regions_free++; |
| 856 | STATS_INC(d->deletes); | 845 | STATS_INC(d->deletes); |
| 857 | 846 | ||
| @@ -936,7 +925,7 @@ omalloc_make_chunks(struct dir_info *d, int bits, int listnum) | |||
| 936 | 925 | ||
| 937 | bits++; | 926 | bits++; |
| 938 | if ((uintptr_t)pp & bits) | 927 | if ((uintptr_t)pp & bits) |
| 939 | wrterror(d, "pp & bits", pp); | 928 | wrterror(d, "pp & bits %p", pp); |
| 940 | 929 | ||
| 941 | insert(d, (void *)((uintptr_t)pp | bits), (uintptr_t)bp, NULL); | 930 | insert(d, (void *)((uintptr_t)pp | bits), (uintptr_t)bp, NULL); |
| 942 | return bp; | 931 | return bp; |
| @@ -956,7 +945,7 @@ malloc_bytes(struct dir_info *d, size_t argsize, void *f) | |||
| 956 | 945 | ||
| 957 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || | 946 | if (mopts.malloc_canary != (d->canary1 ^ (u_int32_t)(uintptr_t)d) || |
| 958 | d->canary1 != ~d->canary2) | 947 | d->canary1 != ~d->canary2) |
| 959 | wrterror(d, "internal struct corrupt", NULL); | 948 | wrterror(d, "internal struct corrupt"); |
| 960 | 949 | ||
| 961 | size = argsize; | 950 | size = argsize; |
| 962 | 951 | ||
| @@ -984,7 +973,7 @@ malloc_bytes(struct dir_info *d, size_t argsize, void *f) | |||
| 984 | } | 973 | } |
| 985 | 974 | ||
| 986 | if (bp->canary != d->canary1) | 975 | if (bp->canary != d->canary1) |
| 987 | wrterror(d, "chunk info corrupted", NULL); | 976 | wrterror(d, "chunk info corrupted"); |
| 988 | 977 | ||
| 989 | i = d->chunk_start; | 978 | i = d->chunk_start; |
| 990 | if (bp->free > 1) | 979 | if (bp->free > 1) |
| @@ -1045,6 +1034,25 @@ malloc_bytes(struct dir_info *d, size_t argsize, void *f) | |||
| 1045 | return ((char *)bp->page + k); | 1034 | return ((char *)bp->page + k); |
| 1046 | } | 1035 | } |
| 1047 | 1036 | ||
| 1037 | static void | ||
| 1038 | validate_canary(struct dir_info *d, u_char *ptr, size_t sz, size_t allocated) | ||
| 1039 | { | ||
| 1040 | size_t check_sz = allocated - sz; | ||
| 1041 | u_char *p, *q; | ||
| 1042 | |||
| 1043 | if (check_sz > CHUNK_CHECK_LENGTH) | ||
| 1044 | check_sz = CHUNK_CHECK_LENGTH; | ||
| 1045 | p = (u_char *)ptr + sz; | ||
| 1046 | q = p + check_sz; | ||
| 1047 | |||
| 1048 | while (p < q) { | ||
| 1049 | if (*p++ != SOME_JUNK) { | ||
| 1050 | wrterror(d, "chunk canary corrupted %p %#tx@%#zx", | ||
| 1051 | ptr, p - ptr - 1, sz); | ||
| 1052 | } | ||
| 1053 | } | ||
| 1054 | } | ||
| 1055 | |||
| 1048 | static uint32_t | 1056 | static uint32_t |
| 1049 | find_chunknum(struct dir_info *d, struct region_info *r, void *ptr, int check) | 1057 | find_chunknum(struct dir_info *d, struct region_info *r, void *ptr, int check) |
| 1050 | { | 1058 | { |
| @@ -1053,32 +1061,20 @@ find_chunknum(struct dir_info *d, struct region_info *r, void *ptr, int check) | |||
| 1053 | 1061 | ||
| 1054 | info = (struct chunk_info *)r->size; | 1062 | info = (struct chunk_info *)r->size; |
| 1055 | if (info->canary != d->canary1) | 1063 | if (info->canary != d->canary1) |
| 1056 | wrterror(d, "chunk info corrupted", NULL); | 1064 | wrterror(d, "chunk info corrupted"); |
| 1057 | 1065 | ||
| 1058 | /* Find the chunk number on the page */ | 1066 | /* Find the chunk number on the page */ |
| 1059 | chunknum = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; | 1067 | chunknum = ((uintptr_t)ptr & MALLOC_PAGEMASK) >> info->shift; |
| 1060 | if (check && mopts.chunk_canaries && info->size > 0) { | 1068 | if (check && mopts.chunk_canaries && info->size > 0) { |
| 1061 | size_t sz = info->bits[info->offset + chunknum]; | 1069 | validate_canary(d, ptr, info->bits[info->offset + chunknum], |
| 1062 | size_t check_sz = info->size - sz; | 1070 | info->size); |
| 1063 | u_char *p, *q; | ||
| 1064 | |||
| 1065 | if (check_sz > CHUNK_CHECK_LENGTH) | ||
| 1066 | check_sz = CHUNK_CHECK_LENGTH; | ||
| 1067 | p = (u_char *)ptr + sz; | ||
| 1068 | q = p + check_sz; | ||
| 1069 | |||
| 1070 | while (p < q) | ||
| 1071 | if (*p++ != SOME_JUNK) { | ||
| 1072 | q = (void *)(sz << 16 | p - (u_char *)ptr - 1); | ||
| 1073 | wrterror(d, "chunk canary corrupted: ", q); | ||
| 1074 | } | ||
| 1075 | } | 1071 | } |
| 1076 | 1072 | ||
| 1077 | if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) | 1073 | if ((uintptr_t)ptr & ((1U << (info->shift)) - 1)) |
| 1078 | wrterror(d, "modified chunk-pointer", ptr); | 1074 | wrterror(d, "modified chunk-pointer %p", ptr); |
| 1079 | if (info->bits[chunknum / MALLOC_BITS] & | 1075 | if (info->bits[chunknum / MALLOC_BITS] & |
| 1080 | (1U << (chunknum % MALLOC_BITS))) | 1076 | (1U << (chunknum % MALLOC_BITS))) |
| 1081 | wrterror(d, "chunk is already free", ptr); | 1077 | wrterror(d, "chunk is already free %p", ptr); |
| 1082 | return chunknum; | 1078 | return chunknum; |
| 1083 | } | 1079 | } |
| 1084 | 1080 | ||
| @@ -1156,7 +1152,7 @@ omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f) | |||
| 1156 | if (mopts.malloc_guard) { | 1152 | if (mopts.malloc_guard) { |
| 1157 | if (mprotect((char *)p + psz - mopts.malloc_guard, | 1153 | if (mprotect((char *)p + psz - mopts.malloc_guard, |
| 1158 | mopts.malloc_guard, PROT_NONE)) | 1154 | mopts.malloc_guard, PROT_NONE)) |
| 1159 | wrterror(pool, "mprotect", NULL); | 1155 | wrterror(pool, "mprotect"); |
| 1160 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); | 1156 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); |
| 1161 | } | 1157 | } |
| 1162 | 1158 | ||
| @@ -1181,6 +1177,14 @@ omalloc(struct dir_info *pool, size_t sz, int zero_fill, void *f) | |||
| 1181 | memset(p, SOME_JUNK, | 1177 | memset(p, SOME_JUNK, |
| 1182 | psz - mopts.malloc_guard); | 1178 | psz - mopts.malloc_guard); |
| 1183 | } | 1179 | } |
| 1180 | else if (mopts.chunk_canaries) { | ||
| 1181 | size_t csz = psz - sz; | ||
| 1182 | |||
| 1183 | if (csz > CHUNK_CHECK_LENGTH) | ||
| 1184 | csz = CHUNK_CHECK_LENGTH; | ||
| 1185 | memset((char *)p + sz - mopts.malloc_guard, | ||
| 1186 | SOME_JUNK, csz); | ||
| 1187 | } | ||
| 1184 | } | 1188 | } |
| 1185 | 1189 | ||
| 1186 | } else { | 1190 | } else { |
| @@ -1205,7 +1209,7 @@ malloc_recurse(struct dir_info *d) | |||
| 1205 | 1209 | ||
| 1206 | if (noprint == 0) { | 1210 | if (noprint == 0) { |
| 1207 | noprint = 1; | 1211 | noprint = 1; |
| 1208 | wrterror(d, "recursive call", NULL); | 1212 | wrterror(d, "recursive call"); |
| 1209 | } | 1213 | } |
| 1210 | d->active--; | 1214 | d->active--; |
| 1211 | _MALLOC_UNLOCK(d->mutex); | 1215 | _MALLOC_UNLOCK(d->mutex); |
| @@ -1264,7 +1268,7 @@ malloc(size_t size) | |||
| 1264 | d = getpool(); | 1268 | d = getpool(); |
| 1265 | } | 1269 | } |
| 1266 | _MALLOC_LOCK(d->mutex); | 1270 | _MALLOC_LOCK(d->mutex); |
| 1267 | d->func = "malloc():"; | 1271 | d->func = "malloc"; |
| 1268 | 1272 | ||
| 1269 | if (d->active++) { | 1273 | if (d->active++) { |
| 1270 | malloc_recurse(d); | 1274 | malloc_recurse(d); |
| @@ -1274,7 +1278,7 @@ malloc(size_t size) | |||
| 1274 | d->active--; | 1278 | d->active--; |
| 1275 | _MALLOC_UNLOCK(d->mutex); | 1279 | _MALLOC_UNLOCK(d->mutex); |
| 1276 | if (r == NULL && mopts.malloc_xmalloc) | 1280 | if (r == NULL && mopts.malloc_xmalloc) |
| 1277 | wrterror(d, "out of memory", NULL); | 1281 | wrterror(d, "out of memory"); |
| 1278 | if (r != NULL) | 1282 | if (r != NULL) |
| 1279 | errno = saved_errno; | 1283 | errno = saved_errno; |
| 1280 | return r; | 1284 | return r; |
| @@ -1291,13 +1295,13 @@ validate_junk(struct dir_info *pool, void *p) | |||
| 1291 | return; | 1295 | return; |
| 1292 | r = find(pool, p); | 1296 | r = find(pool, p); |
| 1293 | if (r == NULL) | 1297 | if (r == NULL) |
| 1294 | wrterror(pool, "bogus pointer in validate_junk", p); | 1298 | wrterror(pool, "bogus pointer in validate_junk %p", p); |
| 1295 | REALSIZE(sz, r); | 1299 | REALSIZE(sz, r); |
| 1296 | if (sz > CHUNK_CHECK_LENGTH) | 1300 | if (sz > CHUNK_CHECK_LENGTH) |
| 1297 | sz = CHUNK_CHECK_LENGTH; | 1301 | sz = CHUNK_CHECK_LENGTH; |
| 1298 | for (byte = 0; byte < sz; byte++) { | 1302 | for (byte = 0; byte < sz; byte++) { |
| 1299 | if (((unsigned char *)p)[byte] != SOME_FREEJUNK) | 1303 | if (((unsigned char *)p)[byte] != SOME_FREEJUNK) |
| 1300 | wrterror(pool, "use after free", p); | 1304 | wrterror(pool, "use after free %p", p); |
| 1301 | } | 1305 | } |
| 1302 | } | 1306 | } |
| 1303 | 1307 | ||
| @@ -1327,7 +1331,7 @@ ofree(struct dir_info *argpool, void *p) | |||
| 1327 | } | 1331 | } |
| 1328 | } | 1332 | } |
| 1329 | if (r == NULL) | 1333 | if (r == NULL) |
| 1330 | wrterror(pool, "bogus pointer (double free?)", p); | 1334 | wrterror(pool, "bogus pointer (double free?) %p", p); |
| 1331 | } | 1335 | } |
| 1332 | 1336 | ||
| 1333 | REALSIZE(sz, r); | 1337 | REALSIZE(sz, r); |
| @@ -1335,7 +1339,11 @@ ofree(struct dir_info *argpool, void *p) | |||
| 1335 | if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE - | 1339 | if (sz - mopts.malloc_guard >= MALLOC_PAGESIZE - |
| 1336 | MALLOC_LEEWAY) { | 1340 | MALLOC_LEEWAY) { |
| 1337 | if (r->p != p) | 1341 | if (r->p != p) |
| 1338 | wrterror(pool, "bogus pointer", p); | 1342 | wrterror(pool, "bogus pointer %p", p); |
| 1343 | if (mopts.chunk_canaries) | ||
| 1344 | validate_canary(pool, p, | ||
| 1345 | sz - mopts.malloc_guard, | ||
| 1346 | PAGEROUND(sz - mopts.malloc_guard)); | ||
| 1339 | } else { | 1347 | } else { |
| 1340 | #if notyetbecause_of_realloc | 1348 | #if notyetbecause_of_realloc |
| 1341 | /* shifted towards the end */ | 1349 | /* shifted towards the end */ |
| @@ -1348,12 +1356,12 @@ ofree(struct dir_info *argpool, void *p) | |||
| 1348 | } | 1356 | } |
| 1349 | if (mopts.malloc_guard) { | 1357 | if (mopts.malloc_guard) { |
| 1350 | if (sz < mopts.malloc_guard) | 1358 | if (sz < mopts.malloc_guard) |
| 1351 | wrterror(pool, "guard size", NULL); | 1359 | wrterror(pool, "guard size"); |
| 1352 | if (!mopts.malloc_freeunmap) { | 1360 | if (!mopts.malloc_freeunmap) { |
| 1353 | if (mprotect((char *)p + PAGEROUND(sz) - | 1361 | if (mprotect((char *)p + PAGEROUND(sz) - |
| 1354 | mopts.malloc_guard, mopts.malloc_guard, | 1362 | mopts.malloc_guard, mopts.malloc_guard, |
| 1355 | PROT_READ | PROT_WRITE)) | 1363 | PROT_READ | PROT_WRITE)) |
| 1356 | wrterror(pool, "mprotect", NULL); | 1364 | wrterror(pool, "mprotect"); |
| 1357 | } | 1365 | } |
| 1358 | STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); | 1366 | STATS_SUB(pool->malloc_guarded, mopts.malloc_guard); |
| 1359 | } | 1367 | } |
| @@ -1371,7 +1379,7 @@ ofree(struct dir_info *argpool, void *p) | |||
| 1371 | tmp = p; | 1379 | tmp = p; |
| 1372 | p = pool->delayed_chunks[i]; | 1380 | p = pool->delayed_chunks[i]; |
| 1373 | if (tmp == p) | 1381 | if (tmp == p) |
| 1374 | wrterror(pool, "double free", p); | 1382 | wrterror(pool, "double free %p", tmp); |
| 1375 | if (mopts.malloc_junk) | 1383 | if (mopts.malloc_junk) |
| 1376 | validate_junk(pool, p); | 1384 | validate_junk(pool, p); |
| 1377 | pool->delayed_chunks[i] = tmp; | 1385 | pool->delayed_chunks[i] = tmp; |
| @@ -1382,11 +1390,12 @@ ofree(struct dir_info *argpool, void *p) | |||
| 1382 | if (p != NULL) { | 1390 | if (p != NULL) { |
| 1383 | r = find(pool, p); | 1391 | r = find(pool, p); |
| 1384 | if (r == NULL) | 1392 | if (r == NULL) |
| 1385 | wrterror(pool, "bogus pointer (double free?)", p); | 1393 | wrterror(pool, |
| 1394 | "bogus pointer (double free?) %p", p); | ||
| 1386 | free_bytes(pool, r, p); | 1395 | free_bytes(pool, r, p); |
| 1387 | } | 1396 | } |
| 1388 | } | 1397 | } |
| 1389 | done: | 1398 | |
| 1390 | if (argpool != pool) { | 1399 | if (argpool != pool) { |
| 1391 | pool->active--; | 1400 | pool->active--; |
| 1392 | _MALLOC_UNLOCK(pool->mutex); | 1401 | _MALLOC_UNLOCK(pool->mutex); |
| @@ -1407,9 +1416,9 @@ free(void *ptr) | |||
| 1407 | 1416 | ||
| 1408 | d = getpool(); | 1417 | d = getpool(); |
| 1409 | if (d == NULL) | 1418 | if (d == NULL) |
| 1410 | wrterror(d, "free() called before allocation", NULL); | 1419 | wrterror(d, "free() called before allocation"); |
| 1411 | _MALLOC_LOCK(d->mutex); | 1420 | _MALLOC_LOCK(d->mutex); |
| 1412 | d->func = "free():"; | 1421 | d->func = "free"; |
| 1413 | if (d->active++) { | 1422 | if (d->active++) { |
| 1414 | malloc_recurse(d); | 1423 | malloc_recurse(d); |
| 1415 | return; | 1424 | return; |
| @@ -1453,7 +1462,7 @@ orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) | |||
| 1453 | } | 1462 | } |
| 1454 | } | 1463 | } |
| 1455 | if (r == NULL) | 1464 | if (r == NULL) |
| 1456 | wrterror(pool, "bogus pointer (double free?)", p); | 1465 | wrterror(pool, "bogus pointer (double free?) %p", p); |
| 1457 | } | 1466 | } |
| 1458 | if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { | 1467 | if (newsz >= SIZE_MAX - mopts.malloc_guard - MALLOC_PAGESIZE) { |
| 1459 | errno = ENOMEM; | 1468 | errno = ENOMEM; |
| @@ -1465,7 +1474,7 @@ orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) | |||
| 1465 | goldsz = oldsz; | 1474 | goldsz = oldsz; |
| 1466 | if (oldsz > MALLOC_MAXCHUNK) { | 1475 | if (oldsz > MALLOC_MAXCHUNK) { |
| 1467 | if (oldsz < mopts.malloc_guard) | 1476 | if (oldsz < mopts.malloc_guard) |
| 1468 | wrterror(pool, "guard size", NULL); | 1477 | wrterror(pool, "guard size"); |
| 1469 | oldsz -= mopts.malloc_guard; | 1478 | oldsz -= mopts.malloc_guard; |
| 1470 | } | 1479 | } |
| 1471 | 1480 | ||
| @@ -1474,7 +1483,7 @@ orealloc(struct dir_info *argpool, void *p, size_t newsz, void *f) | |||
| 1474 | gnewsz += mopts.malloc_guard; | 1483 | gnewsz += mopts.malloc_guard; |
| 1475 | 1484 | ||
| 1476 | if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p && | 1485 | if (newsz > MALLOC_MAXCHUNK && oldsz > MALLOC_MAXCHUNK && p == r->p && |
| 1477 | !mopts.malloc_realloc) { | 1486 | !mopts.chunk_canaries && !mopts.malloc_realloc) { |
| 1478 | size_t roldsz = PAGEROUND(goldsz); | 1487 | size_t roldsz = PAGEROUND(goldsz); |
| 1479 | size_t rnewsz = PAGEROUND(gnewsz); | 1488 | size_t rnewsz = PAGEROUND(gnewsz); |
| 1480 | 1489 | ||
| @@ -1505,7 +1514,7 @@ gotit: | |||
| 1505 | goto done; | 1514 | goto done; |
| 1506 | } else if (q != MAP_FAILED) { | 1515 | } else if (q != MAP_FAILED) { |
| 1507 | if (munmap(q, needed)) | 1516 | if (munmap(q, needed)) |
| 1508 | wrterror(pool, "munmap", q); | 1517 | wrterror(pool, "munmap %p", q); |
| 1509 | } | 1518 | } |
| 1510 | } | 1519 | } |
| 1511 | } else if (rnewsz < roldsz) { | 1520 | } else if (rnewsz < roldsz) { |
| @@ -1513,11 +1522,11 @@ gotit: | |||
| 1513 | if (mprotect((char *)p + roldsz - | 1522 | if (mprotect((char *)p + roldsz - |
| 1514 | mopts.malloc_guard, mopts.malloc_guard, | 1523 | mopts.malloc_guard, mopts.malloc_guard, |
| 1515 | PROT_READ | PROT_WRITE)) | 1524 | PROT_READ | PROT_WRITE)) |
| 1516 | wrterror(pool, "mprotect", NULL); | 1525 | wrterror(pool, "mprotect"); |
| 1517 | if (mprotect((char *)p + rnewsz - | 1526 | if (mprotect((char *)p + rnewsz - |
| 1518 | mopts.malloc_guard, mopts.malloc_guard, | 1527 | mopts.malloc_guard, mopts.malloc_guard, |
| 1519 | PROT_NONE)) | 1528 | PROT_NONE)) |
| 1520 | wrterror(pool, "mprotect", NULL); | 1529 | wrterror(pool, "mprotect"); |
| 1521 | } | 1530 | } |
| 1522 | unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); | 1531 | unmap(pool, (char *)p + rnewsz, roldsz - rnewsz); |
| 1523 | r->size = gnewsz; | 1532 | r->size = gnewsz; |
| @@ -1578,7 +1587,7 @@ realloc(void *ptr, size_t size) | |||
| 1578 | d = getpool(); | 1587 | d = getpool(); |
| 1579 | } | 1588 | } |
| 1580 | _MALLOC_LOCK(d->mutex); | 1589 | _MALLOC_LOCK(d->mutex); |
| 1581 | d->func = "realloc():"; | 1590 | d->func = "realloc"; |
| 1582 | if (d->active++) { | 1591 | if (d->active++) { |
| 1583 | malloc_recurse(d); | 1592 | malloc_recurse(d); |
| 1584 | return NULL; | 1593 | return NULL; |
| @@ -1588,7 +1597,7 @@ realloc(void *ptr, size_t size) | |||
| 1588 | d->active--; | 1597 | d->active--; |
| 1589 | _MALLOC_UNLOCK(d->mutex); | 1598 | _MALLOC_UNLOCK(d->mutex); |
| 1590 | if (r == NULL && mopts.malloc_xmalloc) | 1599 | if (r == NULL && mopts.malloc_xmalloc) |
| 1591 | wrterror(d, "out of memory", NULL); | 1600 | wrterror(d, "out of memory"); |
| 1592 | if (r != NULL) | 1601 | if (r != NULL) |
| 1593 | errno = saved_errno; | 1602 | errno = saved_errno; |
| 1594 | return r; | 1603 | return r; |
| @@ -1615,12 +1624,12 @@ calloc(size_t nmemb, size_t size) | |||
| 1615 | d = getpool(); | 1624 | d = getpool(); |
| 1616 | } | 1625 | } |
| 1617 | _MALLOC_LOCK(d->mutex); | 1626 | _MALLOC_LOCK(d->mutex); |
| 1618 | d->func = "calloc():"; | 1627 | d->func = "calloc"; |
| 1619 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && | 1628 | if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && |
| 1620 | nmemb > 0 && SIZE_MAX / nmemb < size) { | 1629 | nmemb > 0 && SIZE_MAX / nmemb < size) { |
| 1621 | _MALLOC_UNLOCK(d->mutex); | 1630 | _MALLOC_UNLOCK(d->mutex); |
| 1622 | if (mopts.malloc_xmalloc) | 1631 | if (mopts.malloc_xmalloc) |
| 1623 | wrterror(d, "out of memory", NULL); | 1632 | wrterror(d, "out of memory"); |
| 1624 | errno = ENOMEM; | 1633 | errno = ENOMEM; |
| 1625 | return NULL; | 1634 | return NULL; |
| 1626 | } | 1635 | } |
| @@ -1636,7 +1645,7 @@ calloc(size_t nmemb, size_t size) | |||
| 1636 | d->active--; | 1645 | d->active--; |
| 1637 | _MALLOC_UNLOCK(d->mutex); | 1646 | _MALLOC_UNLOCK(d->mutex); |
| 1638 | if (r == NULL && mopts.malloc_xmalloc) | 1647 | if (r == NULL && mopts.malloc_xmalloc) |
| 1639 | wrterror(d, "out of memory", NULL); | 1648 | wrterror(d, "out of memory"); |
| 1640 | if (r != NULL) | 1649 | if (r != NULL) |
| 1641 | errno = saved_errno; | 1650 | errno = saved_errno; |
| 1642 | return r; | 1651 | return r; |
| @@ -1649,9 +1658,9 @@ mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) | |||
| 1649 | char *p, *q; | 1658 | char *p, *q; |
| 1650 | 1659 | ||
| 1651 | if (alignment < MALLOC_PAGESIZE || ((alignment - 1) & alignment) != 0) | 1660 | if (alignment < MALLOC_PAGESIZE || ((alignment - 1) & alignment) != 0) |
| 1652 | wrterror(d, "mapalign bad alignment", NULL); | 1661 | wrterror(d, "mapalign bad alignment"); |
| 1653 | if (sz != PAGEROUND(sz)) | 1662 | if (sz != PAGEROUND(sz)) |
| 1654 | wrterror(d, "mapalign round", NULL); | 1663 | wrterror(d, "mapalign round"); |
| 1655 | 1664 | ||
| 1656 | /* Allocate sz + alignment bytes of memory, which must include a | 1665 | /* Allocate sz + alignment bytes of memory, which must include a |
| 1657 | * subrange of size bytes that is properly aligned. Unmap the | 1666 | * subrange of size bytes that is properly aligned. Unmap the |
| @@ -1668,10 +1677,10 @@ mapalign(struct dir_info *d, size_t alignment, size_t sz, int zero_fill) | |||
| 1668 | q = (char *)(((uintptr_t)p + alignment - 1) & ~(alignment - 1)); | 1677 | q = (char *)(((uintptr_t)p + alignment - 1) & ~(alignment - 1)); |
| 1669 | if (q != p) { | 1678 | if (q != p) { |
| 1670 | if (munmap(p, q - p)) | 1679 | if (munmap(p, q - p)) |
| 1671 | wrterror(d, "munmap", p); | 1680 | wrterror(d, "munmap %p", p); |
| 1672 | } | 1681 | } |
| 1673 | if (munmap(q + sz, alignment - (q - p))) | 1682 | if (munmap(q + sz, alignment - (q - p))) |
| 1674 | wrterror(d, "munmap", q + sz); | 1683 | wrterror(d, "munmap %p", q + sz); |
| 1675 | STATS_SUB(d->malloc_used, alignment); | 1684 | STATS_SUB(d->malloc_used, alignment); |
| 1676 | 1685 | ||
| 1677 | return q; | 1686 | return q; |
| @@ -1716,7 +1725,7 @@ omemalign(struct dir_info *pool, size_t alignment, size_t sz, int zero_fill, voi | |||
| 1716 | if (mopts.malloc_guard) { | 1725 | if (mopts.malloc_guard) { |
| 1717 | if (mprotect((char *)p + psz - mopts.malloc_guard, | 1726 | if (mprotect((char *)p + psz - mopts.malloc_guard, |
| 1718 | mopts.malloc_guard, PROT_NONE)) | 1727 | mopts.malloc_guard, PROT_NONE)) |
| 1719 | wrterror(pool, "mprotect", NULL); | 1728 | wrterror(pool, "mprotect"); |
| 1720 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); | 1729 | STATS_ADD(pool->malloc_guarded, mopts.malloc_guard); |
| 1721 | } | 1730 | } |
| 1722 | 1731 | ||
| @@ -1748,7 +1757,7 @@ posix_memalign(void **memptr, size_t alignment, size_t size) | |||
| 1748 | d = getpool(); | 1757 | d = getpool(); |
| 1749 | } | 1758 | } |
| 1750 | _MALLOC_LOCK(d->mutex); | 1759 | _MALLOC_LOCK(d->mutex); |
| 1751 | d->func = "posix_memalign():"; | 1760 | d->func = "posix_memalign"; |
| 1752 | if (d->active++) { | 1761 | if (d->active++) { |
| 1753 | malloc_recurse(d); | 1762 | malloc_recurse(d); |
| 1754 | goto err; | 1763 | goto err; |
| @@ -1758,7 +1767,7 @@ posix_memalign(void **memptr, size_t alignment, size_t size) | |||
| 1758 | _MALLOC_UNLOCK(d->mutex); | 1767 | _MALLOC_UNLOCK(d->mutex); |
| 1759 | if (r == NULL) { | 1768 | if (r == NULL) { |
| 1760 | if (mopts.malloc_xmalloc) | 1769 | if (mopts.malloc_xmalloc) |
| 1761 | wrterror(d, "out of memory", NULL); | 1770 | wrterror(d, "out of memory"); |
| 1762 | goto err; | 1771 | goto err; |
| 1763 | } | 1772 | } |
| 1764 | errno = saved_errno; | 1773 | errno = saved_errno; |
| @@ -2007,7 +2016,7 @@ malloc_dump(int fd, struct dir_info *pool) | |||
| 2007 | continue; | 2016 | continue; |
| 2008 | r = find(pool, p); | 2017 | r = find(pool, p); |
| 2009 | if (r == NULL) | 2018 | if (r == NULL) |
| 2010 | wrterror(pool, "bogus pointer in malloc_dump", p); | 2019 | wrterror(pool, "bogus pointer in malloc_dump %p", p); |
| 2011 | free_bytes(pool, r, p); | 2020 | free_bytes(pool, r, p); |
| 2012 | pool->delayed_chunks[i] = NULL; | 2021 | pool->delayed_chunks[i] = NULL; |
| 2013 | } | 2022 | } |
