[v2] malloc: Simplify _int_free_chunk

Message ID PAWPR08MB89820A94C8EC2D98F4EB381283122@PAWPR08MB8982.eurprd08.prod.outlook.com (mailing list archive)
State Committed
Commit 49244da1102f56af20a5a462a2ec704dd0dd94fa
Headers
Series [v2] malloc: Simplify _int_free_chunk |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch success Patch applied to master at the time it was sent
linaro-tcwg-bot/tcwg_glibc_build--master-aarch64 success Build passed
redhat-pt-bot/TryBot-32bit success Build for i686
linaro-tcwg-bot/tcwg_glibc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_glibc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_glibc_check--master-arm success Test passed

Commit Message

Wilco Dijkstra June 2, 2026, 3:36 p.m. UTC
  v2: rebased

Simplify _int_free_chunk() and always lock if needed.  Use _int_free_merge_chunk()
for cases that assume the arena has been locked  instead.  Move the errno save/
restore to _int_free_maybe_trim().

Passes regress, OK for commit?

---
  

Comments

Yury Khrustalev June 5, 2026, 1:04 p.m. UTC | #1
On Tue, Jun 02, 2026 at 03:36:48PM +0000, Wilco Dijkstra wrote:
> v2: rebased
> 
> Simplify _int_free_chunk() and always lock if needed.  Use _int_free_merge_chunk()
> for cases that assume the arena has been locked  instead.  Move the errno save/
> restore to _int_free_maybe_trim().
> 
> Passes regress, OK for commit?

LGTM

Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>

The paths that were using '_int_free_chunk (..., chunk, ..., 1)' before
this change were never called for mmap-ed chunks.

Tested on aarch64-linux-gnu, x86_64-pc-linux-gnu, i686-pc-linux-gnu.

Thanks,
Yury
  

Patch

diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
index 8ed419c6e95c2025bad4f865b97da4bf56d2d8f5..b1a10c74b3484ca515a1bb50793073574f863eb9 100644
--- a/malloc/malloc-check.c
+++ b/malloc/malloc-check.c
@@ -224,7 +224,7 @@  free_check (void *mem)
     }
   else
     {
-      _int_free_chunk (&main_arena, p, chunksize (p), 1);
+      _int_free_merge_chunk (&main_arena, p, chunksize (p));
       __libc_lock_unlock (main_arena.mutex);
     }
   __set_errno (err);
diff --git a/malloc/malloc.c b/malloc/malloc.c
index b5b09fb8b0ccd7155ef798a6ece789b2ca3f1e22..dfd9ea81d9165a90f4e37a418f4c827994890c89 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -931,7 +931,7 @@  typedef struct malloc_chunk* mchunkptr;
 /* Internal routines.  */
 
 static void*  _int_malloc(mstate, size_t);
-static void _int_free_chunk (mstate, mchunkptr, INTERNAL_SIZE_T, int);
+static void _int_free_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
 static void _int_free_merge_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
 static INTERNAL_SIZE_T _int_free_create_chunk (mstate,
 					       mchunkptr, INTERNAL_SIZE_T,
@@ -2241,7 +2241,7 @@  sysmalloc (INTERNAL_SIZE_T nb, mstate av)
 			CHUNK_HDR_SZ | PREV_INUSE);
               set_foot (chunk_at_offset (old_top, old_size), CHUNK_HDR_SZ);
               set_head (old_top, old_size | PREV_INUSE | NON_MAIN_ARENA);
-              _int_free_chunk (av, old_top, chunksize (old_top), 1);
+              _int_free_merge_chunk (av, old_top, chunksize (old_top));
             }
           else
             {
@@ -2512,7 +2512,7 @@  sysmalloc (INTERNAL_SIZE_T nb, mstate av)
                       /* If possible, release the rest. */
                       if (old_size >= MINSIZE)
                         {
-                          _int_free_chunk (av, old_top, chunksize (old_top), 1);
+                          _int_free_merge_chunk (av, old_top, chunksize (old_top));
                         }
                     }
                 }
@@ -3009,12 +3009,12 @@  tcache_thread_shutdown (void)
 	  tcache_tmp->entries[i] = REVEAL_PTR (e->next);
 	  e->key = 0;
 	  p = mem2chunk (e);
-	  _int_free_chunk (arena_for_chunk (p), p, chunksize (p), 0);
+	  _int_free_chunk (arena_for_chunk (p), p, chunksize (p));
 	}
     }
 
   p = mem2chunk (tcache_tmp);
-  _int_free_chunk (arena_for_chunk (p), p, chunksize (p), 0);
+  _int_free_chunk (arena_for_chunk (p), p, chunksize (p));
 }
 
 /* Initialize tcache.  In the rare case there isn't any memory available,
@@ -3178,7 +3178,7 @@  __libc_free (void *mem)
 					  size - MINSIZE)))
     return malloc_printerr_tail ("free(): invalid size");
 
-  _int_free_chunk (arena_for_chunk (p), p, size, 0);
+  _int_free_chunk (arena_for_chunk (p), p, size);
 }
 libc_hidden_def (__libc_free)
 
@@ -3285,7 +3285,7 @@  __libc_realloc (void *oldmem, size_t bytes)
       if (newp != NULL)
         {
 	  memcpy (newp, oldmem, memsize (oldp));
-	  _int_free_chunk (ar_ptr, oldp, chunksize (oldp), 0);
+	  _int_free_chunk (ar_ptr, oldp, chunksize (oldp));
         }
     }
 
@@ -4047,11 +4047,10 @@  _int_malloc (mstate av, size_t bytes)
    ------------------------------ free ------------------------------
  */
 
-/* Free chunk P of SIZE bytes to the arena.  HAVE_LOCK indicates where
-   the arena for P has already been locked.  Caller must ensure chunk
-   and size are valid.  */
-static void
-_int_free_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size, int have_lock)
+/* Free chunk P of SIZE bytes to the arena AV (which is not locked).
+   Caller must ensure chunk and size are valid.  */
+static __attribute_maybe_unused__ void
+_int_free_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
 {
   /*
     Consolidate other non-mmapped chunks as they arrive.
@@ -4059,22 +4058,14 @@  _int_free_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size, int have_lock)
 
   if (!chunk_is_mmapped(p)) {
 
-    /* Preserve errno in case block merging results in munmap.  */
-    int err = errno;
-
-    /* If we're single-threaded, don't lock the arena.  */
     if (SINGLE_THREAD_P)
-      have_lock = true;
-
-    if (!have_lock)
-      __libc_lock_lock (av->mutex);
-
-    _int_free_merge_chunk (av, p, size);
-
-    if (!have_lock)
-      __libc_lock_unlock (av->mutex);
-
-    __set_errno (err);
+      _int_free_merge_chunk (av, p, size);
+    else
+      {
+	__libc_lock_lock (av->mutex);
+	_int_free_merge_chunk (av, p, size);
+	__libc_lock_unlock (av->mutex);
+      }
   }
   /*
     If the chunk was allocated via mmap, release via munmap().
@@ -4091,8 +4082,8 @@  _int_free_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size, int have_lock)
   }
 }
 
-/* Try to merge chunk P of SIZE bytes with its neighbors.  Put the
-   resulting chunk on the appropriate bin list.  P must not be on a
+/* Try to merge chunk P of SIZE bytes from locked arena AV with its neighbors.
+   Put the resulting chunk on the appropriate bin list.  P must not be on a
    bin list yet, and it can be in use.  */
 static void
 _int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
@@ -4222,6 +4213,9 @@  _int_free_maybe_trim (mstate av, INTERNAL_SIZE_T size)
      if ATTEMPT_TRIMMING_THRESHOLD is reached.  */
   if (size >= ATTEMPT_TRIMMING_THRESHOLD)
     {
+      /* Preserve errno.  */
+      int err = errno;
+
       if (av == &main_arena)
 	{
 #ifndef MORECORE_CANNOT_TRIM
@@ -4238,6 +4232,8 @@  _int_free_maybe_trim (mstate av, INTERNAL_SIZE_T size)
 	  assert (heap->ar_ptr == av);
 	  heap_trim (heap, mp_.top_pad);
 	}
+
+      __set_errno (err);
     }
 }
 
@@ -4328,7 +4324,7 @@  _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
             {
 	      void *oldmem = chunk2mem (oldp);
 	      memcpy (newmem, oldmem, memsize (oldp));
-	      _int_free_chunk (av, oldp, chunksize (oldp), 1);
+	      _int_free_merge_chunk (av, oldp, chunksize (oldp));
 	      check_inuse_chunk (av, newp);
 	      return newmem;
             }
@@ -4354,7 +4350,7 @@  _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
                 (av != &main_arena ? NON_MAIN_ARENA : 0));
       /* Mark remainder as inuse so free() won't complain */
       set_inuse_bit_at_offset (remainder, remainder_size);
-      _int_free_chunk (av, remainder, chunksize (remainder), 1);
+      _int_free_merge_chunk (av, remainder, chunksize (remainder));
     }
 
   check_inuse_chunk (av, newp);