Re: malloc: more info in error message for write-after-free with option D
Hi, I wanted an extension to malloc() that would report the caller of all memory leaks. It works fine for me! ok asou@ -- ASOU Masato From: Otto Moerbeek Date: Tue, 10 Oct 2023 12:39:00 +0200 > Hi, > > This diff adds better error reporting for write-after-free or the more > general write of free memory if malloc option D is active. Knowing the > place where allocations were done often helps to find out where the > overwrite happened. > > If option D is active malloc now saves caller info in a separate page > instead of only doing that for chunk index 0. It also reports about > the preceding chunk if applicable. A report looks like this: > > X(12489) in calloc(): write to free chunk 0x851ec6066d0[0..7]@16 > allocated at /usr/X11R6/lib/modules/dri/radeonsi_dri.so 0x88c949 > (preceding chunk 0x851ec6066c0 allocated at /usr/X11R6/bin/X 0x177374 (now > free)) > > You can use addr2line -e to get the file and linenumber the allocation > was done (if the object was compiled with debug info). > > If D is not used only the first part is printed, as no caller info is > saved. So no extra overhead if D is not useed. > > Also: the leak report now do not contain unknown locations anymore, as > each allocation gets its caller recorded if D is active. > > -Otto > > Index: stdlib/malloc.3 > === > RCS file: /home/cvs/src/lib/libc/stdlib/malloc.3,v > retrieving revision 1.137 > diff -u -p -r1.137 malloc.3 > --- stdlib/malloc.3 1 Jul 2023 18:35:14 - 1.137 > +++ stdlib/malloc.3 10 Oct 2023 10:23:19 - > @@ -307,7 +307,7 @@ These malloc options imply > .Cm D . > .It Cm F > .Dq Freecheck . > -Enable more extensive double free and use after free detection. > +Enable more extensive double free and write after free detection. > All chunks in the delayed free list will be checked for double frees and > write after frees. > Unused pages on the freelist are read and write protected to > @@ -641,18 +641,34 @@ or > reallocate an unallocated pointer was made. > .It Dq double free > There was an attempt to free an allocation that had already been freed. > -.It Dq write after free > -An allocation has been modified after it was freed. > +.It Dq write of free mem Va address Ns [ Va start Ns .. Ns Va end Ns ]@ Ns > Va size > +An allocation has been modified after it was freed, > +or a chunk that was never allocated was written to. > +The > +.Va range > +at which corruption was detected is printed between [ and ]. > +.Pp > +Enabling option > +.Cm D > +allows malloc to print information about where the allocation > +was done. > .It Dq modified chunk-pointer > The pointer passed to > .Fn free > or a reallocation function has been modified. > -.It Dq canary corrupted address offset@length > -A byte after the requested size has been overwritten, > +.It Dq canary corrupted Va address Ns [ Va offset Ns ]@ Ns Va length Ns / Ns > Va size > +A byte after the requested > +.Va length has been overwritten, > indicating a heap overflow. > -The offset at which corruption was detected is printed before the @, > -and the requested length of the allocation after the @. > -.It Dq recorded size oldsize inconsistent with size > +The > +.Va offset > +at which corruption was detected is printed between [ and ], > +the requested > +.Va length > +of the allocation is printed before the / and the > +.Va size > +of the allocation after the /. > +.It Dq recorded size Va oldsize No inconsistent with Va size > .Fn recallocarray > or > .Fn freezero > @@ -676,7 +692,7 @@ functions nor utilize any other function > (e.g., > .Xr stdio 3 > routines). > -.It Dq unknown char in MALLOC_OPTIONS > +.It Dq unknown char in Ev MALLOC_OPTIONS > We found something we didn't understand. > .It any other error > .Fn malloc > Index: stdlib/malloc.c > === > RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v > retrieving revision 1.290 > diff -u -p -r1.290 malloc.c > --- stdlib/malloc.c 9 Sep 2023 06:52:40 - 1.290 > +++ stdlib/malloc.c 10 Oct 2023 10:23:19 - > @@ -112,7 +112,7 @@ struct region_info { > void *p;/* page; low bits used to mark chunks */ > uintptr_t size; /* size for pages, or chunk_info pointer */ > #ifdef MALLOC_STATS > - void *f;/* where allocated from */ > + void **f; /* where allocated from */ > #endif > }; > > @@ -146,7 +146,7 @@ struct dir_info { > size_t regions_total; /* number of region slots */ > size_t regions_free;/* number of free slots */ > size_t rbytesused; /* random bytes used */ > - char *func; /* current function */ > + const char *func; /* current function */ > int malloc_junk;/* junk fill? */ > int mmap_flag; /* extra flag for mmap */ >
malloc: more info in error message for write-after-free with option D
Hi, This diff adds better error reporting for write-after-free or the more general write of free memory if malloc option D is active. Knowing the place where allocations were done often helps to find out where the overwrite happened. If option D is active malloc now saves caller info in a separate page instead of only doing that for chunk index 0. It also reports about the preceding chunk if applicable. A report looks like this: X(12489) in calloc(): write to free chunk 0x851ec6066d0[0..7]@16 allocated at /usr/X11R6/lib/modules/dri/radeonsi_dri.so 0x88c949 (preceding chunk 0x851ec6066c0 allocated at /usr/X11R6/bin/X 0x177374 (now free)) You can use addr2line -e to get the file and linenumber the allocation was done (if the object was compiled with debug info). If D is not used only the first part is printed, as no caller info is saved. So no extra overhead if D is not useed. Also: the leak report now do not contain unknown locations anymore, as each allocation gets its caller recorded if D is active. -Otto Index: stdlib/malloc.3 === RCS file: /home/cvs/src/lib/libc/stdlib/malloc.3,v retrieving revision 1.137 diff -u -p -r1.137 malloc.3 --- stdlib/malloc.3 1 Jul 2023 18:35:14 - 1.137 +++ stdlib/malloc.3 10 Oct 2023 10:23:19 - @@ -307,7 +307,7 @@ These malloc options imply .Cm D . .It Cm F .Dq Freecheck . -Enable more extensive double free and use after free detection. +Enable more extensive double free and write after free detection. All chunks in the delayed free list will be checked for double frees and write after frees. Unused pages on the freelist are read and write protected to @@ -641,18 +641,34 @@ or reallocate an unallocated pointer was made. .It Dq double free There was an attempt to free an allocation that had already been freed. -.It Dq write after free -An allocation has been modified after it was freed. +.It Dq write of free mem Va address Ns [ Va start Ns .. Ns Va end Ns ]@ Ns Va size +An allocation has been modified after it was freed, +or a chunk that was never allocated was written to. +The +.Va range +at which corruption was detected is printed between [ and ]. +.Pp +Enabling option +.Cm D +allows malloc to print information about where the allocation +was done. .It Dq modified chunk-pointer The pointer passed to .Fn free or a reallocation function has been modified. -.It Dq canary corrupted address offset@length -A byte after the requested size has been overwritten, +.It Dq canary corrupted Va address Ns [ Va offset Ns ]@ Ns Va length Ns / Ns Va size +A byte after the requested +.Va length has been overwritten, indicating a heap overflow. -The offset at which corruption was detected is printed before the @, -and the requested length of the allocation after the @. -.It Dq recorded size oldsize inconsistent with size +The +.Va offset +at which corruption was detected is printed between [ and ], +the requested +.Va length +of the allocation is printed before the / and the +.Va size +of the allocation after the /. +.It Dq recorded size Va oldsize No inconsistent with Va size .Fn recallocarray or .Fn freezero @@ -676,7 +692,7 @@ functions nor utilize any other function (e.g., .Xr stdio 3 routines). -.It Dq unknown char in MALLOC_OPTIONS +.It Dq unknown char in Ev MALLOC_OPTIONS We found something we didn't understand. .It any other error .Fn malloc Index: stdlib/malloc.c === RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v retrieving revision 1.290 diff -u -p -r1.290 malloc.c --- stdlib/malloc.c 9 Sep 2023 06:52:40 - 1.290 +++ stdlib/malloc.c 10 Oct 2023 10:23:19 - @@ -112,7 +112,7 @@ struct region_info { void *p;/* page; low bits used to mark chunks */ uintptr_t size; /* size for pages, or chunk_info pointer */ #ifdef MALLOC_STATS - void *f;/* where allocated from */ + void **f; /* where allocated from */ #endif }; @@ -146,7 +146,7 @@ struct dir_info { size_t regions_total; /* number of region slots */ size_t regions_free;/* number of free slots */ size_t rbytesused; /* random bytes used */ - char *func; /* current function */ + const char *func; /* current function */ int malloc_junk;/* junk fill? */ int mmap_flag; /* extra flag for mmap */ int mutex; @@ -166,6 +166,7 @@ struct dir_info { void *chunk_pages; size_t chunk_pages_used; #ifdef MALLOC_STATS + void *caller; size_t inserts; size_t insert_collisions; size_t finds; @@ -183,12 +184,16 @@ struct dir_info { #define STATS_INC(x) ((x)++) #define STATS_ZERO(x) ((x) = 0) #define STATS_SETF(x,y)((x)->f = (y)) +#define