Hi, this came up after a remark by tb@; it does a more thorough check of the chunks in the delay list if malloc option F (which is included in S).
Catches way more use-after-free's as otherwise we'll have to wait until a chunk is actively re-used. With the new bucket code that might take longer (or not happen at all because the program terminates). The catch also happens closer (in time) to the actual write after free. That might help finding the root cause. -Otto Index: stdlib/malloc.3 =================================================================== RCS file: /home/cvs/src/lib/libc/stdlib/malloc.3,v retrieving revision 1.129 diff -u -p -r1.129 malloc.3 --- stdlib/malloc.3 31 Mar 2022 17:27:16 -0000 1.129 +++ stdlib/malloc.3 30 Mar 2023 14:47:19 -0000 @@ -293,7 +293,8 @@ order to have any effect. .It Cm F .Dq Freecheck . Enable more extensive double free and use after free detection. -All chunks in the delayed free list will be checked for double frees. +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 cause a segmentation fault upon access. .It Cm G Index: stdlib/malloc.c =================================================================== RCS file: /home/cvs/src/lib/libc/stdlib/malloc.c,v retrieving revision 1.278 diff -u -p -r1.278 malloc.c --- stdlib/malloc.c 25 Mar 2023 15:22:06 -0000 1.278 +++ stdlib/malloc.c 30 Mar 2023 14:47:19 -0000 @@ -1554,11 +1554,25 @@ ofree(struct dir_info **argpool, void *p find_chunknum(pool, info, p, mopts.chunk_canaries); if (mopts.malloc_freecheck) { - for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++) - if (p == pool->delayed_chunks[i]) + for (i = 0; i <= MALLOC_DELAYED_CHUNK_MASK; i++) { + tmp = pool->delayed_chunks[i]; + if (tmp == p) wrterror(pool, "double free %p", p); + if (tmp != NULL) { + size_t tmpsz; + + r = find(pool, tmp); + if (r == NULL) + wrterror(pool, + "bogus pointer (" + "double free?) %p", tmp); + REALSIZE(tmpsz, r); + validate_junk(pool, tmp, tmpsz); + } + } } + if (clear && argsz > 0) explicit_bzero(p, argsz); junk_free(pool->malloc_junk, p, sz); @@ -1574,8 +1588,10 @@ ofree(struct dir_info **argpool, void *p if (r == NULL) wrterror(pool, "bogus pointer (double free?) %p", p); - REALSIZE(sz, r); - validate_junk(pool, p, sz); + if (!mopts.malloc_freecheck) { + REALSIZE(sz, r); + validate_junk(pool, p, sz); + } free_bytes(pool, r, p); } }