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);
                }
        }

Reply via email to