test/malloc:alternate path due to memory obstruction test that checks if malloc uses mmap when sbrk fails

Message ID 20240515152838.89944-1-saypaul@redhat.com
State New
Headers
Series test/malloc:alternate path due to memory obstruction test that checks if malloc uses mmap when sbrk fails |

Checks

Context Check Description
redhat-pt-bot/TryBot-apply_patch fail Patch failed to apply to master at the time it was sent
redhat-pt-bot/TryBot-32bit fail Patch series failed to apply

Commit Message

sayan paul May 15, 2024, 3:28 p.m. UTC
  From: Sayan Paul <paul.sayan@gmail.com>

The test aims to ensure that malloc uses the alternate path to
allocate memory when sbrk() or brk() fails.To achieve this,
tst-mmap-obstruction-lib creates an obstruction at the current program break,
which when loaded using LD_PRELOAD  ensures that sbrk() will fail to allocate
any additional memory.However the test script:tst-malloc-alternate-path
checks if malloc is still returning a valid ptr and we can theb infer that
malloc() used mmap() instead of brk() or sbrk() to allocate the memory.
---
 malloc/Makefile                    |   9 ++++
 malloc/tst-malloc-alternate-path   | Bin 0 -> 17000 bytes
 malloc/tst-malloc-alternate-path.c |  69 +++++++++++++++++++++++++++
 malloc/tst-mmap-obstruction-lib.c  |  74 +++++++++++++++++++++++++++++
 4 files changed, 152 insertions(+)
 create mode 100755 malloc/tst-malloc-alternate-path
 create mode 100644 malloc/tst-malloc-alternate-path.c
 create mode 100644 malloc/tst-mmap-obstruction-lib.c

new file mode 100644
index 0000000000..877d8d14a1
  

Comments

Zack Weinberg May 15, 2024, 3:57 p.m. UTC | #1
On Wed, May 15, 2024, at 3:28 PM, sayan paul wrote:
> From: Sayan Paul <paul.sayan@gmail.com>

Should we use your Red Hat address or your Gmail address to communicate
with you about this patch?

> The test aims to ensure that malloc uses the alternate path to
> allocate memory when sbrk() or brk() fails.

I think this is a good test to have.

> To achieve this,
> tst-mmap-obstruction-lib creates an obstruction at the current program break,
> which when loaded using LD_PRELOAD  ensures that sbrk() will fail to allocate
> any additional memory.However the test script:tst-malloc-alternate-path
> checks if malloc is still returning a valid ptr and we can theb infer that
> malloc() used mmap() instead of brk() or sbrk() to allocate the memory.

This seems over-complicated.  Why wouldn't it work to create the obstruction
from inside tst-malloc-alternate-path:do_test(), right after the first call
to sbrk(0)?  If you plan to use the obstruction-creation routine in other tests,
couldn't you make it a test-support function (support/*.c) instead of an
LD_PRELOAD module?

> diff --git a/malloc/tst-malloc-alternate-path 
> b/malloc/tst-malloc-alternate-path
> new file mode 100755
> index 
> 0000000000000000000000000000000000000000..19f0dda0bf90f207785cce833f8839bbcde15854
> GIT binary patch
> literal 17000

Looks like you checked in the compiled test by mistake.  Please remove that
in the next round of this patch.

zw
  

Patch

diff --git a/malloc/Makefile b/malloc/Makefile
index 77ba1a9109..f0fb98d33e 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -33,6 +33,7 @@  tests := \
   tst-interpose-nothread \
   tst-interpose-thread \
   tst-malloc \
+  tst-malloc-alternate-path \
   tst-malloc-backtrace \
   tst-malloc-check \
   tst-malloc-fork-deadlock \
@@ -195,6 +196,7 @@  extra-libs-others = $(extra-libs)
 extra-test-objs += \
   tst-interpose-aux-nothread.o \
   tst-interpose-aux-thread.o \
+  tst-mmap-obstruction-lib.so \
 # extra-test-objs
 
 test-extras = \
@@ -202,6 +204,9 @@  test-extras = \
   tst-interpose-aux-thread \
 # test-extras
 
+modules-names = \
+  tst-mmap-obstruction-lib
+
 libmemusage-routines = memusage
 libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
 
@@ -408,3 +413,7 @@  tst-mallocstate-malloc-check-ENV = LD_PRELOAD=$(objpfx)libc_malloc_debug.so
 # libc_malloc_debug.so.
 $(objpfx)tst-mallocstate: $(objpfx)libc_malloc_debug.so
 $(objpfx)tst-mallocstate-malloc-check: $(objpfx)libc_malloc_debug.so
+
+
+$(objpfx)tst-malloc-alternate-path.out: $(objpfx)tst-mmap-obstruction-lib.so
+tst-malloc-alternate-path-ENV = LD_PRELOAD=$(objpfx)tst-mmap-obstruction-lib.so
diff --git a/malloc/tst-malloc-alternate-path b/malloc/tst-malloc-alternate-path
new file mode 100755
index 0000000000000000000000000000000000000000..19f0dda0bf90f207785cce833f8839bbcde15854
GIT binary patch
literal 17000
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
D=p+U7

literal 0
HcmV?d00001

diff --git a/malloc/tst-malloc-alternate-path.c b/malloc/tst-malloc-alternate-path.c
--- /dev/null
+++ b/malloc/tst-malloc-alternate-path.c
@@ -0,0 +1,69 @@ 
+/* Test malloc that uses mmap when sbrk or brk fails.
+   This code returns success when there is an obstruction setup
+   and sbrk() fails to grow the heap size forcing malloc to use mmap().
+   Copyright (C) 2024 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#define LARGE_SIZE (10 * (1 << 20)) // 10 MB
+
+static int
+do_test (void)
+{
+  /* Get current program break */
+  void *current_brk = sbrk (0);
+
+  /* Try to extend the heap beyond the obstruction using sbrk */
+  int *ptr = (int *) sbrk (sizeof (int));
+  if (ptr != (void *) -1)
+    {
+      fprintf (stderr, "memory allocation can be done using sbrk.\n");
+      free (ptr);
+      return 1;
+    }
+
+  /* Attempt to allocate memory using malloc */
+  void *memptr = malloc (LARGE_SIZE);
+  if (memptr == NULL)
+    {
+      perror ("malloc");
+      return 1;
+    }
+
+  printf ("malloc used alternate path to allocate memory\n");
+
+  /* Get program break after malloc */
+  void *new_brk = sbrk (0);
+
+  /* Check if malloc changed program break */
+  if (current_brk != new_brk)
+    {
+      fprintf (stderr, "malloc changed program break\n");
+      free (memptr);
+      return 1;
+    }
+
+  free (memptr);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/malloc/tst-mmap-obstruction-lib.c b/malloc/tst-mmap-obstruction-lib.c
new file mode 100644
index 0000000000..61e35c7f55
--- /dev/null
+++ b/malloc/tst-mmap-obstruction-lib.c
@@ -0,0 +1,74 @@ 
+/* Module used for creating a memory obstruction using mmap
+   Copyright (C) 2024 Free Software Foundation, Inc.
+   Copyright The GNU Toolchain Authors.
+   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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libc-pointer-arith.h>
+
+static void *obstruction_addr = NULL;
+static long page_size;
+
+/* ELF constructor to set up the obstruction */
+static void obstruction_setup (void) __attribute__ ((constructor));
+
+/* ELF destructor to teardown the obstruction */
+static void obstruction_teardown (void) __attribute__ ((destructor));
+
+static void
+obstruction_setup (void)
+{
+  /* Get the runtime page size */
+  page_size = sysconf (_SC_PAGESIZE);
+
+  /* Get current program break */
+  void *current_brk = sbrk (0);
+
+  /* Round up to the next page boundary */
+  void *next_page_boundary = PTR_ALIGN_UP (current_brk, page_size);
+
+  /* Place a mapping using mmap at the next page boundary */
+  obstruction_addr
+      = mmap (next_page_boundary, page_size, PROT_WRITE | PROT_READ,
+	      MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+  if (obstruction_addr == MAP_FAILED)
+    {
+      perror ("mmap");
+      obstruction_addr = NULL;
+    }
+
+  if (obstruction_addr != next_page_boundary)
+    {
+      fprintf (stderr, "memory obstruction not setup correctly!");
+    }
+}
+
+/* Function to teardown the obstruction mapping */
+static void
+obstruction_teardown (void)
+{
+  /* Free the obstruction mapping */
+  if (obstruction_addr && munmap (obstruction_addr, page_size) == -1)
+    {
+      perror ("munmap");
+    }
+}