Index: kern_malloc.c =================================================================== RCS file: /cvs/src/sys/kern/kern_malloc.c,v retrieving revision 1.128 diff -u -p -r1.128 kern_malloc.c --- kern_malloc.c 14 Mar 2015 03:38:50 -0000 1.128 +++ kern_malloc.c 28 Apr 2015 11:14:17 -0000 @@ -40,6 +40,7 @@ #include #include #include +#include #include @@ -117,9 +118,9 @@ struct rwlock sysctl_kmemlock = RWLOCK_I * helps to detect memory reuse problems and avoid free list corruption. */ struct kmem_freelist { - int32_t kf_spare0; + const char *kf_file; int16_t kf_type; - int16_t kf_spare1; + int16_t kf_line; XSIMPLEQ_ENTRY(kmem_freelist) kf_flist; }; @@ -141,11 +142,44 @@ struct timeval malloc_errintvl = { 5, 0 struct timeval malloc_lasterr; #endif +void malloc_chk(void *); +struct timeout malloc_tick = TIMEOUT_INITIALIZER(malloc_chk, NULL); + +void +malloc_chk(void *null) +{ + static int indx = MINBUCKET; + struct kmembuckets *kbp = &bucket[indx]; + struct kmem_freelist *freep; + size_t sz = 1 << indx; + size_t pidx; + u_int32_t word; + int s; + + s = splvm(); + XSIMPLEQ_FOREACH(freep, &kbp->kb_freelist, kf_flist) { + if (poison_check(freep + 1, sz - sizeof(*freep), + &pidx, &word)) { + const char *type = freep->kf_type < M_LAST ? + memname[freep->kf_type] : "???"; + panic("%s: %s data modified in %p+%zu, free() %s[%u]", + __func__, type, freep, sz, + freep->kf_file, freep->kf_line); + } + } + splx(s); + + if (++indx >= nitems(bucket)) + indx = MINBUCKET; + + timeout_add(&malloc_tick, 1); +} + /* * Allocate a block of memory */ void * -malloc(size_t size, int type, int flags) +__ktr_malloc(const char *f, u_int l, size_t size, int type, int flags) { struct kmembuckets *kbp; struct kmemusage *kup; @@ -241,6 +275,8 @@ malloc(size_t size, int type, int flags) splx(s); return (NULL); } + ktr_ext(f, l, "uvm_km_kmemalloc_pla", memname[type], + va, ptoa(npg)); #ifdef KMEMSTATS kbp->kb_total += kbp->kb_elmpercl; #endif @@ -268,8 +304,10 @@ malloc(size_t size, int type, int flags) * Copy in known text to detect modification * after freeing. */ - poison_mem(cp, allocsize); + freep->kf_file = __FILE__; freep->kf_type = M_FREE; + freep->kf_line = __LINE__; + poison_mem(freep + 1, allocsize - sizeof(*freep)); #endif /* DIAGNOSTIC */ XSIMPLEQ_INSERT_HEAD(&kbp->kb_freelist, freep, kf_flist); if (cp <= va) @@ -305,23 +343,20 @@ malloc(size_t size, int type, int flags) } } - /* Fill the fields that we've used with poison */ - poison_mem(freep, sizeof(*freep)); - /* and check that the data hasn't been modified. */ if (freshalloc == 0) { size_t pidx; uint32_t pval; - if (poison_check(va, allocsize, &pidx, &pval)) { - panic("%s %zd of object %p size 0x%lx %s %s" - " (0x%x != 0x%x)\n", - "Data modified on freelist: word", - pidx, va, size, "previous type", - savedtype, ((int32_t*)va)[pidx], pval); + if (poison_check(freep + 1, allocsize - sizeof(*freep), + &pidx, &pval)) { + const char *type = freep->kf_type < M_LAST ? + memname[freep->kf_type] : "???"; + panic("%s: %s data modified in %p+%zu, free() %s[%u]", + __func__, type, freep, allocsize, + freep->kf_file, freep->kf_line); } } - freep->kf_spare0 = 0; #endif /* DIAGNOSTIC */ #ifdef KMEMSTATS kup = btokup(va); @@ -345,6 +380,8 @@ out: if ((flags & M_ZERO) && va != NULL) memset(va, 0, size); + if (va != NULL) + ktr_ext(f, l, "malloc", savedtype, va, allocsize); return (va); } @@ -352,7 +389,7 @@ out: * Free a block of memory allocated by malloc. */ void -free(void *addr, int type, size_t freedsize) +__ktr_free(const char *f, u_int l, void *addr, int type, size_t freedsize) { struct kmembuckets *kbp; struct kmemusage *kup; @@ -385,6 +422,9 @@ free(void *addr, int type, size_t freeds kbp = &bucket[kup->ku_indx]; if (size > MAXALLOCSAVE) size = kup->ku_pagecnt << PAGE_SHIFT; + + ktr_ext(f, l, "free", memname[type], addr, size); + s = splvm(); #ifdef DIAGNOSTIC if (freedsize != 0 && freedsize > size) @@ -406,6 +446,8 @@ free(void *addr, int type, size_t freeds addr, size, memname[type], alloc); #endif /* DIAGNOSTIC */ if (size > MAXALLOCSAVE) { + ktr_ext(f, l, "uvm_km_free", memname[type], + addr, ptoa(kup->ku_pagecnt)); uvm_km_free(kmem_map, (vaddr_t)addr, ptoa(kup->ku_pagecnt)); #ifdef KMEMSTATS ksp->ks_memuse -= size; @@ -422,6 +464,7 @@ free(void *addr, int type, size_t freeds } freep = (struct kmem_freelist *)addr; #ifdef DIAGNOSTIC + #if 0 /* * Check for multiple frees. Use a quick check to see if * it looks free before laboriously searching the freelist. @@ -435,16 +478,18 @@ free(void *addr, int type, size_t freeds panic("free: duplicated free"); } } + #endif /* * Copy in known text to detect modification after freeing * and to make it look free. Also, save the type being freed * so we can list likely culprit if modification is detected * when the object is reallocated. */ - poison_mem(addr, size); - freep->kf_spare0 = poison_value(freep); + freep->kf_file = f; freep->kf_type = type; + freep->kf_line = l; + poison_mem(freep + 1, size - sizeof(*freep)); #endif /* DIAGNOSTIC */ #ifdef KMEMSTATS kup->ku_freecnt++; @@ -562,6 +607,7 @@ kmeminit(void) #ifdef MALLOC_DEBUG debug_malloc_init(); #endif + timeout_add(&malloc_tick, 1); } /* @@ -719,7 +765,8 @@ malloc_printit( #define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4)) void * -mallocarray(size_t nmemb, size_t size, int type, int flags) +__ktr_mallocarray(const char *f, u_int l, + size_t nmemb, size_t size, int type, int flags) { if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && nmemb > 0 && SIZE_MAX / nmemb < size) { @@ -727,5 +774,5 @@ mallocarray(size_t nmemb, size_t size, i return (NULL); panic("mallocarray: overflow %zu * %zu", nmemb, size); } - return (malloc(size * nmemb, type, flags)); + return (__ktr_malloc(f, l, size * nmemb, type, flags)); }