diff mbox

malloc: Ensure tcache count won't overflow

Message ID 85673514.nCShmV6Tfd@amaris.nx
State Superseded, archived
Headers show

Commit Message

Adam Maris Nov. 13, 2018, 12:03 p.m. UTC
Fixes bug 23733. This patch replaces the assert on tcache->entries
with tcache->counts in tcache_get() which was probably done by mistake.
If tcache->entries were 0, it would segfault when dereferencing e anyway.
This will make sure the chunks are not served from empty tcache bin
in case the pointer to next chunk of last chunk in tcache gets corrupted.

Includes test case. Tested with no regressions.

	* malloc/Makefile: Add new test.
	* malloc/malloc.c (tcache_get): Check if tcache count > 0.
	* malloc/tst-tcache-count.c: New.
diff mbox

Patch

diff --git a/malloc/Makefile b/malloc/Makefile
index 7d54bad866..508208f24b 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -38,6 +38,7 @@  tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
         tst-malloc_info \
         tst-malloc-too-large \
         tst-malloc-stats-cancellation \
+        tst-malloc-tcache-count \
 
 tests-static := \
         tst-interpose-static-nothread \
diff --git a/malloc/malloc.c b/malloc/malloc.c
index bfc605aa3e..0a0e8a5863 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2930,7 +2930,7 @@  tcache_get (size_t tc_idx)
 {
   tcache_entry *e = tcache->entries[tc_idx];
   assert (tc_idx < TCACHE_MAX_BINS);
-  assert (tcache->entries[tc_idx] > 0);
+  assert (tcache->counts[tc_idx] > 0);
   tcache->entries[tc_idx] = e->next;
   --(tcache->counts[tc_idx]);
   return (void *) e;
diff --git a/malloc/tst-malloc-tcache-count.c b/malloc/tst-malloc-tcache-count.c
index e69de29bb2..bd832dd7e5 100644
--- a/malloc/tst-malloc-tcache-count.c
+++ b/malloc/tst-malloc-tcache-count.c
@@ -0,0 +1,54 @@ 
+/* Ensure tcache count won't overflow, serving chunks from empty tcache bin
+   Copyright (C) 2015-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdlib.h>
+#include <support/check.h>
+#include <string.h>
+#include <signal.h>
+
+// SZ - arbitrary size to fit the chunk in tcache
+#define SZ 32
+
+/* this is to prevent compiler from optimizing out
+   the test code */
+#pragma GCC optimize ("O0")
+
+static int
+do_test (void)
+{
+  void* p = malloc(SZ);
+  void* q = malloc(SZ);
+
+  free(p);
+  free(q);
+
+  // corrupt the next pointer of last chunk in tcache
+  memcpy(p, &q, sizeof(void*));
+
+  malloc(SZ);
+  malloc(SZ);
+  malloc(SZ);
+
+  FAIL_RET("no assertion due to tcache chunk corruption");
+}
+
+#pragma GCC optimize ("O3")
+
+#define EXPECTED_SIGNAL SIGABRT
+#include <support/test-driver.c>