[Feature][ZXW-33]merge ZXW 0428 version

Change-Id: I11f167edfea428d9fab198ff00ff1364932d1b0b
diff --git a/ap/libc/glibc/glibc-2.23/malloc/Depend b/ap/libc/glibc/glibc-2.23/malloc/Depend
new file mode 100644
index 0000000..910c6d9
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/Depend
@@ -0,0 +1 @@
+dlfcn
diff --git a/ap/libc/glibc/glibc-2.23/malloc/Makefile b/ap/libc/glibc/glibc-2.23/malloc/Makefile
new file mode 100644
index 0000000..360288b
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/Makefile
@@ -0,0 +1,169 @@
+# Copyright (C) 1991-2016 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/>.
+
+#
+#	Makefile for malloc routines
+#
+subdir	:= malloc
+
+include ../Makeconfig
+
+dist-headers := malloc.h
+headers := $(dist-headers) obstack.h mcheck.h
+tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
+	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
+	 tst-malloc-usable tst-realloc tst-posix_memalign \
+	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
+	 tst-malloc-backtrace tst-malloc-thread-exit \
+	 tst-malloc-thread-fail
+test-srcs = tst-mtrace
+
+routines = malloc morecore mcheck mtrace obstack \
+  scratch_buffer_grow scratch_buffer_grow_preserve \
+  scratch_buffer_set_array_size
+
+install-lib := libmcheck.a
+non-lib.a := libmcheck.a
+
+# Additional library.
+extra-libs = libmemusage
+extra-libs-others = $(extra-libs)
+
+libmemusage-routines = memusage
+libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
+
+$(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \
+			       $(common-objpfx)nptl/libpthread_nonshared.a
+$(objpfx)tst-malloc-thread-exit: $(common-objpfx)nptl/libpthread.so \
+			       $(common-objpfx)nptl/libpthread_nonshared.a
+$(objpfx)tst-malloc-thread-fail: $(common-objpfx)nptl/libpthread.so \
+			       $(common-objpfx)nptl/libpthread_nonshared.a
+
+# These should be removed by `make clean'.
+extra-objs = mcheck-init.o libmcheck.a
+
+# Include the cleanup handler.
+aux := set-freeres thread-freeres
+
+# The Perl script to analyze the output of the mtrace functions.
+ifneq ($(PERL),no)
+install-bin-script = mtrace
+generated += mtrace
+
+# The Perl script will print addresses and to do this nicely we must know
+# whether we are on a 32 or 64 bit machine.
+ifneq ($(findstring wordsize-32,$(config-sysdirs)),)
+address-width=10
+else
+address-width=18
+endif
+endif
+
+# Unless we get a test for the availability of libgd which also works
+# for cross-compiling we disable the memusagestat generation in this
+# situation.
+ifneq ($(cross-compiling),yes)
+# If the gd library is available we build the `memusagestat' program.
+ifneq ($(LIBGD),no)
+others: $(objpfx)memusage
+install-bin = memusagestat
+install-bin-script += memusage
+generated += memusagestat memusage
+extra-objs += memusagestat.o
+
+# The configure.ac check for libgd and its headers did not use $SYSINCLUDES.
+# The directory specified by --with-headers usually contains only the basic
+# kernel interface headers, not something like libgd.  So the simplest thing
+# is to presume that the standard system headers will be ok for this file.
+$(objpfx)memusagestat.o: sysincludes = # nothing
+endif
+endif
+
+# Another goal which can be used to override the configure decision.
+.PHONY: do-memusagestat
+do-memusagestat: $(objpfx)memusagestat
+
+memusagestat-modules = memusagestat
+
+cpp-srcs-left := $(memusagestat-modules)
+lib := memusagestat
+include $(patsubst %,$(..)cppflags-iterator.mk,$(cpp-srcs-left))
+
+$(objpfx)memusagestat: $(memusagestat-modules:%=$(objpfx)%.o)
+	$(LINK.o) -o $@ $^ $(libgd-LDFLAGS) -lgd -lpng -lz -lm
+
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+tests-special += $(objpfx)tst-mtrace.out
+endif
+endif
+endif
+
+include ../Rules
+
+CFLAGS-mcheck-init.c = $(PIC-ccflag)
+CFLAGS-obstack.c = $(uses-callbacks)
+
+$(objpfx)libmcheck.a: $(objpfx)mcheck-init.o
+	-rm -f $@
+	$(patsubst %/,cd % &&,$(objpfx)) \
+	$(LN_S) $(<F) $(@F)
+
+lib: $(objpfx)libmcheck.a
+
+ifeq ($(run-built-tests),yes)
+ifeq (yes,$(build-shared))
+ifneq ($(PERL),no)
+$(objpfx)tst-mtrace.out: tst-mtrace.sh $(objpfx)tst-mtrace
+	$(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \
+		 '$(run-program-env)' '$(test-program-prefix-after-env)' ; \
+	$(evaluate-test)
+endif
+endif
+endif
+
+tst-mcheck-ENV = MALLOC_CHECK_=3
+tst-malloc-usable-ENV = MALLOC_CHECK_=3
+
+# Uncomment this for test releases.  For public releases it is too expensive.
+#CPPFLAGS-malloc.o += -DMALLOC_DEBUG=1
+
+sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,')
+
+$(objpfx)mtrace: mtrace.pl
+	rm -f $@.new
+	sed -e 's|@PERL@|$(PERL)|' -e 's|@XXX@|$(address-width)|' \
+	    -e 's|@VERSION@|$(version)|' \
+	    -e 's|@PKGVERSION@|$(PKGVERSION)|' \
+	    -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \
+	&& rm -f $@ && mv $@.new $@ && chmod +x $@
+
+$(objpfx)memusage: memusage.sh
+	rm -f $@.new
+	sed -e 's|@BASH@|$(BASH)|' -e 's|@VERSION@|$(version)|' \
+	    -e 's|@SLIBDIR@|$(sLIBdir)|' -e 's|@BINDIR@|$(bindir)|' \
+	    -e 's|@PKGVERSION@|$(PKGVERSION)|' \
+	    -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \
+	&& rm -f $@ && mv $@.new $@ && chmod +x $@
+
+
+# The implementation uses `dlsym'
+$(objpfx)libmemusage.so: $(libdl)
+
+# Extra dependencies
+$(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c
diff --git a/ap/libc/glibc/glibc-2.23/malloc/Versions b/ap/libc/glibc/glibc-2.23/malloc/Versions
new file mode 100644
index 0000000..f3c3d8a
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/Versions
@@ -0,0 +1,76 @@
+libc {
+  GLIBC_2.0 {
+    # global variables
+    _obstack;
+
+    # interface of malloc functions
+    __libc_calloc; __libc_free; __libc_mallinfo; __libc_malloc;
+    __libc_mallopt; __libc_memalign; __libc_pvalloc; __libc_realloc;
+    __libc_valloc;
+    __malloc_initialize_hook; __free_hook; __malloc_hook; __realloc_hook;
+    __memalign_hook; __after_morecore_hook;
+    __malloc_initialized; __default_morecore; __morecore;
+
+    # functions used in inline functions or macros
+    _obstack_allocated_p; _obstack_begin; _obstack_begin_1;
+    _obstack_free; _obstack_memory_used; _obstack_newchunk;
+
+    # variables in normal name space
+    mallwatch; obstack_alloc_failed_handler; obstack_exit_failure;
+
+    # c*
+    calloc; cfree;
+
+    # f*
+    free;
+
+    # m*
+    mallinfo; malloc; malloc_get_state; malloc_set_state; malloc_stats;
+    malloc_trim; malloc_usable_size; mallopt; memalign; mprobe; mtrace;
+    muntrace;
+
+    # o*
+    obstack_free;
+
+    # p*
+    pvalloc;
+
+    # r*
+    realloc;
+
+    # t*
+    tr_break;
+
+    # v*
+    valloc;
+  }
+  GLIBC_2.1 {
+    # Special functions.
+    __libc_freeres;
+  }
+  GLIBC_2.2 {
+    # m*
+    mcheck_check_all; mcheck_pedantic;
+
+    # p*
+    posix_memalign;
+  }
+  GLIBC_2.10 {
+    malloc_info;
+  }
+  GLIBC_2.16 {
+    aligned_alloc;
+  }
+  GLIBC_PRIVATE {
+    # Internal startup hook for libpthread.
+    __libc_malloc_pthread_startup;
+
+    # Internal destructor hook for libpthread.
+    __libc_thread_freeres;
+
+    # struct scratch_buffer support
+    __libc_scratch_buffer_grow;
+    __libc_scratch_buffer_grow_preserve;
+    __libc_scratch_buffer_set_array_size;
+  }
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/arena.c b/ap/libc/glibc/glibc-2.23/malloc/arena.c
new file mode 100644
index 0000000..1edb4d4
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/arena.c
@@ -0,0 +1,1046 @@
+/* Malloc implementation for multiple threads without lock contention.
+   Copyright (C) 2001-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include <stdbool.h>
+
+/* Compile-time constants.  */
+
+#define HEAP_MIN_SIZE (32 * 1024)
+#ifndef HEAP_MAX_SIZE
+# ifdef DEFAULT_MMAP_THRESHOLD_MAX
+#  define HEAP_MAX_SIZE (2 * DEFAULT_MMAP_THRESHOLD_MAX)
+# else
+#  define HEAP_MAX_SIZE (1024 * 1024) /* must be a power of two */
+# endif
+#endif
+
+/* HEAP_MIN_SIZE and HEAP_MAX_SIZE limit the size of mmap()ed heaps
+   that are dynamically created for multi-threaded programs.  The
+   maximum size must be a power of two, for fast determination of
+   which heap belongs to a chunk.  It should be much larger than the
+   mmap threshold, so that requests with a size just below that
+   threshold can be fulfilled without creating too many heaps.  */
+
+/***************************************************************************/
+
+#define top(ar_ptr) ((ar_ptr)->top)
+
+/* A heap is a single contiguous memory region holding (coalesceable)
+   malloc_chunks.  It is allocated with mmap() and always starts at an
+   address aligned to HEAP_MAX_SIZE.  */
+
+typedef struct _heap_info
+{
+  mstate ar_ptr; /* Arena for this heap. */
+  struct _heap_info *prev; /* Previous heap. */
+  size_t size;   /* Current size in bytes. */
+  size_t mprotect_size; /* Size in bytes that has been mprotected
+                           PROT_READ|PROT_WRITE.  */
+  /* Make sure the following data is properly aligned, particularly
+     that sizeof (heap_info) + 2 * SIZE_SZ is a multiple of
+     MALLOC_ALIGNMENT. */
+  char pad[-6 * SIZE_SZ & MALLOC_ALIGN_MASK];
+} heap_info;
+
+/* Get a compile-time error if the heap_info padding is not correct
+   to make alignment work as expected in sYSMALLOc.  */
+extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
+                                             + 2 * SIZE_SZ) % MALLOC_ALIGNMENT
+                                            ? -1 : 1];
+
+/* Thread specific data.  */
+
+static __thread mstate thread_arena attribute_tls_model_ie;
+
+/* Arena free list.  free_list_lock synchronizes access to the
+   free_list variable below, and the next_free and attached_threads
+   members of struct malloc_state objects.  No other locks must be
+   acquired after free_list_lock has been acquired.  */
+
+static mutex_t free_list_lock = _LIBC_LOCK_INITIALIZER;
+static size_t narenas = 1;
+static mstate free_list;
+
+/* list_lock prevents concurrent writes to the next member of struct
+   malloc_state objects.
+
+   Read access to the next member is supposed to synchronize with the
+   atomic_write_barrier and the write to the next member in
+   _int_new_arena.  This suffers from data races; see the FIXME
+   comments in _int_new_arena and reused_arena.
+
+   list_lock also prevents concurrent forks.  At the time list_lock is
+   acquired, no arena lock must have been acquired, but it is
+   permitted to acquire arena locks subsequently, while list_lock is
+   acquired.  */
+static mutex_t list_lock = _LIBC_LOCK_INITIALIZER;
+
+/* Mapped memory in non-main arenas (reliable only for NO_THREADS). */
+static unsigned long arena_mem;
+
+/* Already initialized? */
+int __malloc_initialized = -1;
+
+/**************************************************************************/
+
+
+/* arena_get() acquires an arena and locks the corresponding mutex.
+   First, try the one last locked successfully by this thread.  (This
+   is the common case and handled with a macro for speed.)  Then, loop
+   once over the circularly linked list of arenas.  If no arena is
+   readily available, create a new one.  In this latter case, `size'
+   is just a hint as to how much memory will be required immediately
+   in the new arena. */
+
+#define arena_get(ptr, size) do { \
+      ptr = thread_arena;						      \
+      arena_lock (ptr, size);						      \
+  } while (0)
+
+#define arena_lock(ptr, size) do {					      \
+      if (ptr && !arena_is_corrupt (ptr))				      \
+        (void) mutex_lock (&ptr->mutex);				      \
+      else								      \
+        ptr = arena_get2 ((size), NULL);				      \
+  } while (0)
+
+/* find the heap and corresponding arena for a given ptr */
+
+#define heap_for_ptr(ptr) \
+  ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))
+#define arena_for_chunk(ptr) \
+  (chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)
+
+
+/**************************************************************************/
+
+#ifndef NO_THREADS
+
+/* atfork support.  */
+
+static void *(*save_malloc_hook)(size_t __size, const void *);
+static void (*save_free_hook) (void *__ptr, const void *);
+static void *save_arena;
+
+# ifdef ATFORK_MEM
+ATFORK_MEM;
+# endif
+
+/* Magic value for the thread-specific arena pointer when
+   malloc_atfork() is in use.  */
+
+# define ATFORK_ARENA_PTR ((void *) -1)
+
+/* The following hooks are used while the `atfork' handling mechanism
+   is active. */
+
+static void *
+malloc_atfork (size_t sz, const void *caller)
+{
+  void *victim;
+
+  if (thread_arena == ATFORK_ARENA_PTR)
+    {
+      /* We are the only thread that may allocate at all.  */
+      if (save_malloc_hook != malloc_check)
+        {
+          return _int_malloc (&main_arena, sz);
+        }
+      else
+        {
+          if (top_check () < 0)
+            return 0;
+
+          victim = _int_malloc (&main_arena, sz + 1);
+          return mem2mem_check (victim, sz);
+        }
+    }
+  else
+    {
+      /* Suspend the thread until the `atfork' handlers have completed.
+         By that time, the hooks will have been reset as well, so that
+         mALLOc() can be used again. */
+      (void) mutex_lock (&list_lock);
+      (void) mutex_unlock (&list_lock);
+      return __libc_malloc (sz);
+    }
+}
+
+static void
+free_atfork (void *mem, const void *caller)
+{
+  mstate ar_ptr;
+  mchunkptr p;                          /* chunk corresponding to mem */
+
+  if (mem == 0)                              /* free(0) has no effect */
+    return;
+
+  p = mem2chunk (mem);         /* do not bother to replicate free_check here */
+
+  if (chunk_is_mmapped (p))                       /* release mmapped memory. */
+    {
+      munmap_chunk (p);
+      return;
+    }
+
+  ar_ptr = arena_for_chunk (p);
+  _int_free (ar_ptr, p, thread_arena == ATFORK_ARENA_PTR);
+}
+
+
+/* Counter for number of times the list is locked by the same thread.  */
+static unsigned int atfork_recursive_cntr;
+
+/* The following two functions are registered via thread_atfork() to
+   make sure that the mutexes remain in a consistent state in the
+   fork()ed version of a thread.  Also adapt the malloc and free hooks
+   temporarily, because the `atfork' handler mechanism may use
+   malloc/free internally (e.g. in LinuxThreads). */
+
+static void
+ptmalloc_lock_all (void)
+{
+  mstate ar_ptr;
+
+  if (__malloc_initialized < 1)
+    return;
+
+  /* We do not acquire free_list_lock here because we completely
+     reconstruct free_list in ptmalloc_unlock_all2.  */
+
+  if (mutex_trylock (&list_lock))
+    {
+      if (thread_arena == ATFORK_ARENA_PTR)
+        /* This is the same thread which already locks the global list.
+           Just bump the counter.  */
+        goto out;
+
+      /* This thread has to wait its turn.  */
+      (void) mutex_lock (&list_lock);
+    }
+  for (ar_ptr = &main_arena;; )
+    {
+      (void) mutex_lock (&ar_ptr->mutex);
+      ar_ptr = ar_ptr->next;
+      if (ar_ptr == &main_arena)
+        break;
+    }
+  save_malloc_hook = __malloc_hook;
+  save_free_hook = __free_hook;
+  __malloc_hook = malloc_atfork;
+  __free_hook = free_atfork;
+  /* Only the current thread may perform malloc/free calls now.
+     save_arena will be reattached to the current thread, in
+     ptmalloc_lock_all, so save_arena->attached_threads is not
+     updated.  */
+  save_arena = thread_arena;
+  thread_arena = ATFORK_ARENA_PTR;
+out:
+  ++atfork_recursive_cntr;
+}
+
+static void
+ptmalloc_unlock_all (void)
+{
+  mstate ar_ptr;
+
+  if (__malloc_initialized < 1)
+    return;
+
+  if (--atfork_recursive_cntr != 0)
+    return;
+
+  /* Replace ATFORK_ARENA_PTR with save_arena.
+     save_arena->attached_threads was not changed in ptmalloc_lock_all
+     and is still correct.  */
+  thread_arena = save_arena;
+  __malloc_hook = save_malloc_hook;
+  __free_hook = save_free_hook;
+  for (ar_ptr = &main_arena;; )
+    {
+      (void) mutex_unlock (&ar_ptr->mutex);
+      ar_ptr = ar_ptr->next;
+      if (ar_ptr == &main_arena)
+        break;
+    }
+  (void) mutex_unlock (&list_lock);
+}
+
+# ifdef __linux__
+
+/* In NPTL, unlocking a mutex in the child process after a
+   fork() is currently unsafe, whereas re-initializing it is safe and
+   does not leak resources.  Therefore, a special atfork handler is
+   installed for the child. */
+
+static void
+ptmalloc_unlock_all2 (void)
+{
+  mstate ar_ptr;
+
+  if (__malloc_initialized < 1)
+    return;
+
+  thread_arena = save_arena;
+  __malloc_hook = save_malloc_hook;
+  __free_hook = save_free_hook;
+
+  /* Push all arenas to the free list, except save_arena, which is
+     attached to the current thread.  */
+  mutex_init (&free_list_lock);
+  if (save_arena != NULL)
+    ((mstate) save_arena)->attached_threads = 1;
+  free_list = NULL;
+  for (ar_ptr = &main_arena;; )
+    {
+      mutex_init (&ar_ptr->mutex);
+      if (ar_ptr != save_arena)
+        {
+	  /* This arena is no longer attached to any thread.  */
+	  ar_ptr->attached_threads = 0;
+          ar_ptr->next_free = free_list;
+          free_list = ar_ptr;
+        }
+      ar_ptr = ar_ptr->next;
+      if (ar_ptr == &main_arena)
+        break;
+    }
+
+  mutex_init (&list_lock);
+  atfork_recursive_cntr = 0;
+}
+
+# else
+
+#  define ptmalloc_unlock_all2 ptmalloc_unlock_all
+# endif
+#endif  /* !NO_THREADS */
+
+/* Initialization routine. */
+#include <string.h>
+extern char **_environ;
+
+static char *
+internal_function
+next_env_entry (char ***position)
+{
+  char **current = *position;
+  char *result = NULL;
+
+  while (*current != NULL)
+    {
+      if (__builtin_expect ((*current)[0] == 'M', 0)
+          && (*current)[1] == 'A'
+          && (*current)[2] == 'L'
+          && (*current)[3] == 'L'
+          && (*current)[4] == 'O'
+          && (*current)[5] == 'C'
+          && (*current)[6] == '_')
+        {
+          result = &(*current)[7];
+
+          /* Save current position for next visit.  */
+          *position = ++current;
+
+          break;
+        }
+
+      ++current;
+    }
+
+  return result;
+}
+
+
+#ifdef SHARED
+static void *
+__failing_morecore (ptrdiff_t d)
+{
+  return (void *) MORECORE_FAILURE;
+}
+
+extern struct dl_open_hook *_dl_open_hook;
+libc_hidden_proto (_dl_open_hook);
+#endif
+
+static void
+ptmalloc_init (void)
+{
+  if (__malloc_initialized >= 0)
+    return;
+
+  __malloc_initialized = 0;
+
+#ifdef SHARED
+  /* In case this libc copy is in a non-default namespace, never use brk.
+     Likewise if dlopened from statically linked program.  */
+  Dl_info di;
+  struct link_map *l;
+
+  if (_dl_open_hook != NULL
+      || (_dl_addr (ptmalloc_init, &di, &l, NULL) != 0
+          && l->l_ns != LM_ID_BASE))
+    __morecore = __failing_morecore;
+#endif
+
+  thread_arena = &main_arena;
+  thread_atfork (ptmalloc_lock_all, ptmalloc_unlock_all, ptmalloc_unlock_all2);
+  const char *s = NULL;
+  if (__glibc_likely (_environ != NULL))
+    {
+      char **runp = _environ;
+      char *envline;
+
+      while (__builtin_expect ((envline = next_env_entry (&runp)) != NULL,
+                               0))
+        {
+          size_t len = strcspn (envline, "=");
+
+          if (envline[len] != '=')
+            /* This is a "MALLOC_" variable at the end of the string
+               without a '=' character.  Ignore it since otherwise we
+               will access invalid memory below.  */
+            continue;
+
+          switch (len)
+            {
+            case 6:
+              if (memcmp (envline, "CHECK_", 6) == 0)
+                s = &envline[7];
+              break;
+            case 8:
+              if (!__builtin_expect (__libc_enable_secure, 0))
+                {
+                  if (memcmp (envline, "TOP_PAD_", 8) == 0)
+                    __libc_mallopt (M_TOP_PAD, atoi (&envline[9]));
+                  else if (memcmp (envline, "PERTURB_", 8) == 0)
+                    __libc_mallopt (M_PERTURB, atoi (&envline[9]));
+                }
+              break;
+            case 9:
+              if (!__builtin_expect (__libc_enable_secure, 0))
+                {
+                  if (memcmp (envline, "MMAP_MAX_", 9) == 0)
+                    __libc_mallopt (M_MMAP_MAX, atoi (&envline[10]));
+                  else if (memcmp (envline, "ARENA_MAX", 9) == 0)
+                    __libc_mallopt (M_ARENA_MAX, atoi (&envline[10]));
+                }
+              break;
+            case 10:
+              if (!__builtin_expect (__libc_enable_secure, 0))
+                {
+                  if (memcmp (envline, "ARENA_TEST", 10) == 0)
+                    __libc_mallopt (M_ARENA_TEST, atoi (&envline[11]));
+                }
+              break;
+            case 15:
+              if (!__builtin_expect (__libc_enable_secure, 0))
+                {
+                  if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0)
+                    __libc_mallopt (M_TRIM_THRESHOLD, atoi (&envline[16]));
+                  else if (memcmp (envline, "MMAP_THRESHOLD_", 15) == 0)
+                    __libc_mallopt (M_MMAP_THRESHOLD, atoi (&envline[16]));
+                }
+              break;
+            default:
+              break;
+            }
+        }
+    }
+  if (s && s[0])
+    {
+      __libc_mallopt (M_CHECK_ACTION, (int) (s[0] - '0'));
+      if (check_action != 0)
+        __malloc_check_init ();
+    }
+  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
+  if (hook != NULL)
+    (*hook)();
+  __malloc_initialized = 1;
+}
+
+/* There are platforms (e.g. Hurd) with a link-time hook mechanism. */
+#ifdef thread_atfork_static
+thread_atfork_static (ptmalloc_lock_all, ptmalloc_unlock_all,		      \
+                      ptmalloc_unlock_all2)
+#endif
+
+
+
+/* Managing heaps and arenas (for concurrent threads) */
+
+#if MALLOC_DEBUG > 1
+
+/* Print the complete contents of a single heap to stderr. */
+
+static void
+dump_heap (heap_info *heap)
+{
+  char *ptr;
+  mchunkptr p;
+
+  fprintf (stderr, "Heap %p, size %10lx:\n", heap, (long) heap->size);
+  ptr = (heap->ar_ptr != (mstate) (heap + 1)) ?
+        (char *) (heap + 1) : (char *) (heap + 1) + sizeof (struct malloc_state);
+  p = (mchunkptr) (((unsigned long) ptr + MALLOC_ALIGN_MASK) &
+                   ~MALLOC_ALIGN_MASK);
+  for (;; )
+    {
+      fprintf (stderr, "chunk %p size %10lx", p, (long) p->size);
+      if (p == top (heap->ar_ptr))
+        {
+          fprintf (stderr, " (top)\n");
+          break;
+        }
+      else if (p->size == (0 | PREV_INUSE))
+        {
+          fprintf (stderr, " (fence)\n");
+          break;
+        }
+      fprintf (stderr, "\n");
+      p = next_chunk (p);
+    }
+}
+#endif /* MALLOC_DEBUG > 1 */
+
+/* If consecutive mmap (0, HEAP_MAX_SIZE << 1, ...) calls return decreasing
+   addresses as opposed to increasing, new_heap would badly fragment the
+   address space.  In that case remember the second HEAP_MAX_SIZE part
+   aligned to HEAP_MAX_SIZE from last mmap (0, HEAP_MAX_SIZE << 1, ...)
+   call (if it is already aligned) and try to reuse it next time.  We need
+   no locking for it, as kernel ensures the atomicity for us - worst case
+   we'll call mmap (addr, HEAP_MAX_SIZE, ...) for some value of addr in
+   multiple threads, but only one will succeed.  */
+static char *aligned_heap_area;
+
+/* Create a new heap.  size is automatically rounded up to a multiple
+   of the page size. */
+
+static heap_info *
+internal_function
+new_heap (size_t size, size_t top_pad)
+{
+  size_t pagesize = GLRO (dl_pagesize);
+  char *p1, *p2;
+  unsigned long ul;
+  heap_info *h;
+
+  if (size + top_pad < HEAP_MIN_SIZE)
+    size = HEAP_MIN_SIZE;
+  else if (size + top_pad <= HEAP_MAX_SIZE)
+    size += top_pad;
+  else if (size > HEAP_MAX_SIZE)
+    return 0;
+  else
+    size = HEAP_MAX_SIZE;
+  size = ALIGN_UP (size, pagesize);
+
+  /* A memory region aligned to a multiple of HEAP_MAX_SIZE is needed.
+     No swap space needs to be reserved for the following large
+     mapping (on Linux, this is the case for all non-writable mappings
+     anyway). */
+  p2 = MAP_FAILED;
+  if (aligned_heap_area)
+    {
+      p2 = (char *) MMAP (aligned_heap_area, HEAP_MAX_SIZE, PROT_NONE,
+                          MAP_NORESERVE);
+      aligned_heap_area = NULL;
+      if (p2 != MAP_FAILED && ((unsigned long) p2 & (HEAP_MAX_SIZE - 1)))
+        {
+          __munmap (p2, HEAP_MAX_SIZE);
+          p2 = MAP_FAILED;
+        }
+    }
+  if (p2 == MAP_FAILED)
+    {
+      p1 = (char *) MMAP (0, HEAP_MAX_SIZE << 1, PROT_NONE, MAP_NORESERVE);
+      if (p1 != MAP_FAILED)
+        {
+          p2 = (char *) (((unsigned long) p1 + (HEAP_MAX_SIZE - 1))
+                         & ~(HEAP_MAX_SIZE - 1));
+          ul = p2 - p1;
+          if (ul)
+            __munmap (p1, ul);
+          else
+            aligned_heap_area = p2 + HEAP_MAX_SIZE;
+          __munmap (p2 + HEAP_MAX_SIZE, HEAP_MAX_SIZE - ul);
+        }
+      else
+        {
+          /* Try to take the chance that an allocation of only HEAP_MAX_SIZE
+             is already aligned. */
+          p2 = (char *) MMAP (0, HEAP_MAX_SIZE, PROT_NONE, MAP_NORESERVE);
+          if (p2 == MAP_FAILED)
+            return 0;
+
+          if ((unsigned long) p2 & (HEAP_MAX_SIZE - 1))
+            {
+              __munmap (p2, HEAP_MAX_SIZE);
+              return 0;
+            }
+        }
+    }
+  if (__mprotect (p2, size, PROT_READ | PROT_WRITE) != 0)
+    {
+      __munmap (p2, HEAP_MAX_SIZE);
+      return 0;
+    }
+  h = (heap_info *) p2;
+  h->size = size;
+  h->mprotect_size = size;
+  LIBC_PROBE (memory_heap_new, 2, h, h->size);
+  return h;
+}
+
+/* Grow a heap.  size is automatically rounded up to a
+   multiple of the page size. */
+
+static int
+grow_heap (heap_info *h, long diff)
+{
+  size_t pagesize = GLRO (dl_pagesize);
+  long new_size;
+
+  diff = ALIGN_UP (diff, pagesize);
+  new_size = (long) h->size + diff;
+  if ((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE)
+    return -1;
+
+  if ((unsigned long) new_size > h->mprotect_size)
+    {
+      if (__mprotect ((char *) h + h->mprotect_size,
+                      (unsigned long) new_size - h->mprotect_size,
+                      PROT_READ | PROT_WRITE) != 0)
+        return -2;
+
+      h->mprotect_size = new_size;
+    }
+
+  h->size = new_size;
+  LIBC_PROBE (memory_heap_more, 2, h, h->size);
+  return 0;
+}
+
+/* Shrink a heap.  */
+
+static int
+shrink_heap (heap_info *h, long diff)
+{
+  long new_size;
+
+  new_size = (long) h->size - diff;
+  if (new_size < (long) sizeof (*h))
+    return -1;
+
+  /* Try to re-map the extra heap space freshly to save memory, and make it
+     inaccessible.  See malloc-sysdep.h to know when this is true.  */
+  if (__glibc_unlikely (check_may_shrink_heap ()))
+    {
+      if ((char *) MMAP ((char *) h + new_size, diff, PROT_NONE,
+                         MAP_FIXED) == (char *) MAP_FAILED)
+        return -2;
+
+      h->mprotect_size = new_size;
+    }
+  else
+    __madvise ((char *) h + new_size, diff, MADV_DONTNEED);
+  /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
+
+  h->size = new_size;
+  LIBC_PROBE (memory_heap_less, 2, h, h->size);
+  return 0;
+}
+
+/* Delete a heap. */
+
+#define delete_heap(heap) \
+  do {									      \
+      if ((char *) (heap) + HEAP_MAX_SIZE == aligned_heap_area)		      \
+        aligned_heap_area = NULL;					      \
+      __munmap ((char *) (heap), HEAP_MAX_SIZE);			      \
+    } while (0)
+
+static int
+internal_function
+heap_trim (heap_info *heap, size_t pad)
+{
+  mstate ar_ptr = heap->ar_ptr;
+  unsigned long pagesz = GLRO (dl_pagesize);
+  mchunkptr top_chunk = top (ar_ptr), p, bck, fwd;
+  heap_info *prev_heap;
+  long new_size, top_size, top_area, extra, prev_size, misalign;
+
+  /* Can this heap go away completely? */
+  while (top_chunk == chunk_at_offset (heap, sizeof (*heap)))
+    {
+      prev_heap = heap->prev;
+      prev_size = prev_heap->size - (MINSIZE - 2 * SIZE_SZ);
+      p = chunk_at_offset (prev_heap, prev_size);
+      /* fencepost must be properly aligned.  */
+      misalign = ((long) p) & MALLOC_ALIGN_MASK;
+      p = chunk_at_offset (prev_heap, prev_size - misalign);
+      assert (p->size == (0 | PREV_INUSE)); /* must be fencepost */
+      p = prev_chunk (p);
+      new_size = chunksize (p) + (MINSIZE - 2 * SIZE_SZ) + misalign;
+      assert (new_size > 0 && new_size < (long) (2 * MINSIZE));
+      if (!prev_inuse (p))
+        new_size += p->prev_size;
+      assert (new_size > 0 && new_size < HEAP_MAX_SIZE);
+      if (new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz)
+        break;
+      ar_ptr->system_mem -= heap->size;
+      arena_mem -= heap->size;
+      LIBC_PROBE (memory_heap_free, 2, heap, heap->size);
+      delete_heap (heap);
+      heap = prev_heap;
+      if (!prev_inuse (p)) /* consolidate backward */
+        {
+          p = prev_chunk (p);
+          unlink (ar_ptr, p, bck, fwd);
+        }
+      assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0);
+      assert (((char *) p + new_size) == ((char *) heap + heap->size));
+      top (ar_ptr) = top_chunk = p;
+      set_head (top_chunk, new_size | PREV_INUSE);
+      /*check_chunk(ar_ptr, top_chunk);*/
+    }
+
+  /* Uses similar logic for per-thread arenas as the main arena with systrim
+     and _int_free by preserving the top pad and rounding down to the nearest
+     page.  */
+  top_size = chunksize (top_chunk);
+  if ((unsigned long)(top_size) <
+      (unsigned long)(mp_.trim_threshold))
+    return 0;
+
+  top_area = top_size - MINSIZE - 1;
+  if (top_area < 0 || (size_t) top_area <= pad)
+    return 0;
+
+  /* Release in pagesize units and round down to the nearest page.  */
+  extra = ALIGN_DOWN(top_area - pad, pagesz);
+  if (extra == 0)
+    return 0;
+
+  /* Try to shrink. */
+  if (shrink_heap (heap, extra) != 0)
+    return 0;
+
+  ar_ptr->system_mem -= extra;
+  arena_mem -= extra;
+
+  /* Success. Adjust top accordingly. */
+  set_head (top_chunk, (top_size - extra) | PREV_INUSE);
+  /*check_chunk(ar_ptr, top_chunk);*/
+  return 1;
+}
+
+/* Create a new arena with initial size "size".  */
+
+/* If REPLACED_ARENA is not NULL, detach it from this thread.  Must be
+   called while free_list_lock is held.  */
+static void
+detach_arena (mstate replaced_arena)
+{
+  if (replaced_arena != NULL)
+    {
+      assert (replaced_arena->attached_threads > 0);
+      /* The current implementation only detaches from main_arena in
+	 case of allocation failure.  This means that it is likely not
+	 beneficial to put the arena on free_list even if the
+	 reference count reaches zero.  */
+      --replaced_arena->attached_threads;
+    }
+}
+
+static mstate
+_int_new_arena (size_t size)
+{
+  mstate a;
+  heap_info *h;
+  char *ptr;
+  unsigned long misalign;
+
+  h = new_heap (size + (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT),
+                mp_.top_pad);
+  if (!h)
+    {
+      /* Maybe size is too large to fit in a single heap.  So, just try
+         to create a minimally-sized arena and let _int_malloc() attempt
+         to deal with the large request via mmap_chunk().  */
+      h = new_heap (sizeof (*h) + sizeof (*a) + MALLOC_ALIGNMENT, mp_.top_pad);
+      if (!h)
+        return 0;
+    }
+  a = h->ar_ptr = (mstate) (h + 1);
+  malloc_init_state (a);
+  a->attached_threads = 1;
+  /*a->next = NULL;*/
+  a->system_mem = a->max_system_mem = h->size;
+  arena_mem += h->size;
+
+  /* Set up the top chunk, with proper alignment. */
+  ptr = (char *) (a + 1);
+  misalign = (unsigned long) chunk2mem (ptr) & MALLOC_ALIGN_MASK;
+  if (misalign > 0)
+    ptr += MALLOC_ALIGNMENT - misalign;
+  top (a) = (mchunkptr) ptr;
+  set_head (top (a), (((char *) h + h->size) - ptr) | PREV_INUSE);
+
+  LIBC_PROBE (memory_arena_new, 2, a, size);
+  mstate replaced_arena = thread_arena;
+  thread_arena = a;
+  mutex_init (&a->mutex);
+
+  (void) mutex_lock (&list_lock);
+
+  /* Add the new arena to the global list.  */
+  a->next = main_arena.next;
+  /* FIXME: The barrier is an attempt to synchronize with read access
+     in reused_arena, which does not acquire list_lock while
+     traversing the list.  */
+  atomic_write_barrier ();
+  main_arena.next = a;
+
+  (void) mutex_unlock (&list_lock);
+
+  (void) mutex_lock (&free_list_lock);
+  detach_arena (replaced_arena);
+  (void) mutex_unlock (&free_list_lock);
+
+  /* Lock this arena.  NB: Another thread may have been attached to
+     this arena because the arena is now accessible from the
+     main_arena.next list and could have been picked by reused_arena.
+     This can only happen for the last arena created (before the arena
+     limit is reached).  At this point, some arena has to be attached
+     to two threads.  We could acquire the arena lock before list_lock
+     to make it less likely that reused_arena picks this new arena,
+     but this could result in a deadlock with ptmalloc_lock_all.  */
+
+  (void) mutex_lock (&a->mutex);
+
+  return a;
+}
+
+
+/* Remove an arena from free_list.  The arena may be in use because it
+   was attached concurrently to a thread by reused_arena below.  */
+static mstate
+get_free_list (void)
+{
+  mstate replaced_arena = thread_arena;
+  mstate result = free_list;
+  if (result != NULL)
+    {
+      (void) mutex_lock (&free_list_lock);
+      result = free_list;
+      if (result != NULL)
+	{
+	  free_list = result->next_free;
+
+	  /* The arena will be attached to this thread.  */
+	  ++result->attached_threads;
+
+	  detach_arena (replaced_arena);
+	}
+      (void) mutex_unlock (&free_list_lock);
+
+      if (result != NULL)
+        {
+          LIBC_PROBE (memory_arena_reuse_free_list, 1, result);
+          (void) mutex_lock (&result->mutex);
+	  thread_arena = result;
+        }
+    }
+
+  return result;
+}
+
+/* Lock and return an arena that can be reused for memory allocation.
+   Avoid AVOID_ARENA as we have already failed to allocate memory in
+   it and it is currently locked.  */
+static mstate
+reused_arena (mstate avoid_arena)
+{
+  mstate result;
+  /* FIXME: Access to next_to_use suffers from data races.  */
+  static mstate next_to_use;
+  if (next_to_use == NULL)
+    next_to_use = &main_arena;
+
+  /* Iterate over all arenas (including those linked from
+     free_list).  */
+  result = next_to_use;
+  do
+    {
+      if (!arena_is_corrupt (result) && !mutex_trylock (&result->mutex))
+        goto out;
+
+      /* FIXME: This is a data race, see _int_new_arena.  */
+      result = result->next;
+    }
+  while (result != next_to_use);
+
+  /* Avoid AVOID_ARENA as we have already failed to allocate memory
+     in that arena and it is currently locked.   */
+  if (result == avoid_arena)
+    result = result->next;
+
+  /* Make sure that the arena we get is not corrupted.  */
+  mstate begin = result;
+  while (arena_is_corrupt (result) || result == avoid_arena)
+    {
+      result = result->next;
+      if (result == begin)
+	break;
+    }
+
+  /* We could not find any arena that was either not corrupted or not the one
+     we wanted to avoid.  */
+  if (result == begin || result == avoid_arena)
+    return NULL;
+
+  /* No arena available without contention.  Wait for the next in line.  */
+  LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
+  (void) mutex_lock (&result->mutex);
+
+out:
+  /* Attach the arena to the current thread.  Note that we may have
+     selected an arena which was on free_list.  */
+  {
+    /* Update the arena thread attachment counters.   */
+    mstate replaced_arena = thread_arena;
+    (void) mutex_lock (&free_list_lock);
+    detach_arena (replaced_arena);
+    ++result->attached_threads;
+    (void) mutex_unlock (&free_list_lock);
+  }
+
+  LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
+  thread_arena = result;
+  next_to_use = result->next;
+
+  return result;
+}
+
+static mstate
+internal_function
+arena_get2 (size_t size, mstate avoid_arena)
+{
+  mstate a;
+
+  static size_t narenas_limit;
+
+  a = get_free_list ();
+  if (a == NULL)
+    {
+      /* Nothing immediately available, so generate a new arena.  */
+      if (narenas_limit == 0)
+        {
+          if (mp_.arena_max != 0)
+            narenas_limit = mp_.arena_max;
+          else if (narenas > mp_.arena_test)
+            {
+              int n = __get_nprocs ();
+
+              if (n >= 1)
+                narenas_limit = NARENAS_FROM_NCORES (n);
+              else
+                /* We have no information about the system.  Assume two
+                   cores.  */
+                narenas_limit = NARENAS_FROM_NCORES (2);
+            }
+        }
+    repeat:;
+      size_t n = narenas;
+      /* NB: the following depends on the fact that (size_t)0 - 1 is a
+         very large number and that the underflow is OK.  If arena_max
+         is set the value of arena_test is irrelevant.  If arena_test
+         is set but narenas is not yet larger or equal to arena_test
+         narenas_limit is 0.  There is no possibility for narenas to
+         be too big for the test to always fail since there is not
+         enough address space to create that many arenas.  */
+      if (__glibc_unlikely (n <= narenas_limit - 1))
+        {
+          if (catomic_compare_and_exchange_bool_acq (&narenas, n + 1, n))
+            goto repeat;
+          a = _int_new_arena (size);
+	  if (__glibc_unlikely (a == NULL))
+            catomic_decrement (&narenas);
+        }
+      else
+        a = reused_arena (avoid_arena);
+    }
+  return a;
+}
+
+/* If we don't have the main arena, then maybe the failure is due to running
+   out of mmapped areas, so we can try allocating on the main arena.
+   Otherwise, it is likely that sbrk() has failed and there is still a chance
+   to mmap(), so try one of the other arenas.  */
+static mstate
+arena_get_retry (mstate ar_ptr, size_t bytes)
+{
+  LIBC_PROBE (memory_arena_retry, 2, bytes, ar_ptr);
+  if (ar_ptr != &main_arena)
+    {
+      (void) mutex_unlock (&ar_ptr->mutex);
+      /* Don't touch the main arena if it is corrupt.  */
+      if (arena_is_corrupt (&main_arena))
+	return NULL;
+
+      ar_ptr = &main_arena;
+      (void) mutex_lock (&ar_ptr->mutex);
+    }
+  else
+    {
+      (void) mutex_unlock (&ar_ptr->mutex);
+      ar_ptr = arena_get2 (bytes, ar_ptr);
+    }
+
+  return ar_ptr;
+}
+
+static void __attribute__ ((section ("__libc_thread_freeres_fn")))
+arena_thread_freeres (void)
+{
+  mstate a = thread_arena;
+  thread_arena = NULL;
+
+  if (a != NULL)
+    {
+      (void) mutex_lock (&free_list_lock);
+      /* If this was the last attached thread for this arena, put the
+	 arena on the free list.  */
+      assert (a->attached_threads > 0);
+      if (--a->attached_threads == 0)
+	{
+	  a->next_free = free_list;
+	  free_list = a;
+	}
+      (void) mutex_unlock (&free_list_lock);
+    }
+}
+text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
+
+/*
+ * Local variables:
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/hooks.c b/ap/libc/glibc/glibc-2.23/malloc/hooks.c
new file mode 100644
index 0000000..7a85136
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/hooks.c
@@ -0,0 +1,670 @@
+/* Malloc implementation for multiple threads without lock contention.
+   Copyright (C) 2001-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+/* What to do if the standard debugging hooks are in place and a
+   corrupt pointer is detected: do nothing (0), print an error message
+   (1), or call abort() (2). */
+
+/* Hooks for debugging versions.  The initial hooks just call the
+   initialization routine, then do the normal work. */
+
+static void *
+malloc_hook_ini (size_t sz, const void *caller)
+{
+  __malloc_hook = NULL;
+  ptmalloc_init ();
+  return __libc_malloc (sz);
+}
+
+static void *
+realloc_hook_ini (void *ptr, size_t sz, const void *caller)
+{
+  __malloc_hook = NULL;
+  __realloc_hook = NULL;
+  ptmalloc_init ();
+  return __libc_realloc (ptr, sz);
+}
+
+static void *
+memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
+{
+  __memalign_hook = NULL;
+  ptmalloc_init ();
+  return __libc_memalign (alignment, sz);
+}
+
+/* Whether we are using malloc checking.  */
+static int using_malloc_checking;
+
+/* A flag that is set by malloc_set_state, to signal that malloc checking
+   must not be enabled on the request from the user (via the MALLOC_CHECK_
+   environment variable).  It is reset by __malloc_check_init to tell
+   malloc_set_state that the user has requested malloc checking.
+
+   The purpose of this flag is to make sure that malloc checking is not
+   enabled when the heap to be restored was constructed without malloc
+   checking, and thus does not contain the required magic bytes.
+   Otherwise the heap would be corrupted by calls to free and realloc.  If
+   it turns out that the heap was created with malloc checking and the
+   user has requested it malloc_set_state just calls __malloc_check_init
+   again to enable it.  On the other hand, reusing such a heap without
+   further malloc checking is safe.  */
+static int disallow_malloc_check;
+
+/* Activate a standard set of debugging hooks. */
+void
+__malloc_check_init (void)
+{
+  if (disallow_malloc_check)
+    {
+      disallow_malloc_check = 0;
+      return;
+    }
+  using_malloc_checking = 1;
+  __malloc_hook = malloc_check;
+  __free_hook = free_check;
+  __realloc_hook = realloc_check;
+  __memalign_hook = memalign_check;
+}
+
+/* A simple, standard set of debugging hooks.  Overhead is `only' one
+   byte per chunk; still this will catch most cases of double frees or
+   overruns.  The goal here is to avoid obscure crashes due to invalid
+   usage, unlike in the MALLOC_DEBUG code. */
+
+static unsigned char
+magicbyte (const void *p)
+{
+  unsigned char magic;
+
+  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
+  /* Do not return 1.  See the comment in mem2mem_check().  */
+  if (magic == 1)
+    ++magic;
+  return magic;
+}
+
+
+/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
+   highest address of the chunk, downwards.  The end of each block tells
+   us the size of that block, up to the actual size of the requested
+   memory.  Our magic byte is right at the end of the requested size, so we
+   must reach it with this iteration, otherwise we have witnessed a memory
+   corruption.  */
+static size_t
+malloc_check_get_size (mchunkptr p)
+{
+  size_t size;
+  unsigned char c;
+  unsigned char magic = magicbyte (p);
+
+  assert (using_malloc_checking == 1);
+
+  for (size = chunksize (p) - 1 + (chunk_is_mmapped (p) ? 0 : SIZE_SZ);
+       (c = ((unsigned char *) p)[size]) != magic;
+       size -= c)
+    {
+      if (c <= 0 || size < (c + 2 * SIZE_SZ))
+        {
+          malloc_printerr (check_action, "malloc_check_get_size: memory corruption",
+                           chunk2mem (p),
+			   chunk_is_mmapped (p) ? NULL : arena_for_chunk (p));
+          return 0;
+        }
+    }
+
+  /* chunk2mem size.  */
+  return size - 2 * SIZE_SZ;
+}
+
+/* Instrument a chunk with overrun detector byte(s) and convert it
+   into a user pointer with requested size req_sz. */
+
+static void *
+internal_function
+mem2mem_check (void *ptr, size_t req_sz)
+{
+  mchunkptr p;
+  unsigned char *m_ptr = ptr;
+  size_t max_sz, block_sz, i;
+  unsigned char magic;
+
+  if (!ptr)
+    return ptr;
+
+  p = mem2chunk (ptr);
+  magic = magicbyte (p);
+  max_sz = chunksize (p) - 2 * SIZE_SZ;
+  if (!chunk_is_mmapped (p))
+    max_sz += SIZE_SZ;
+  for (i = max_sz - 1; i > req_sz; i -= block_sz)
+    {
+      block_sz = MIN (i - req_sz, 0xff);
+      /* Don't allow the magic byte to appear in the chain of length bytes.
+         For the following to work, magicbyte cannot return 0x01.  */
+      if (block_sz == magic)
+        --block_sz;
+
+      m_ptr[i] = block_sz;
+    }
+  m_ptr[req_sz] = magic;
+  return (void *) m_ptr;
+}
+
+/* Convert a pointer to be free()d or realloc()ed to a valid chunk
+   pointer.  If the provided pointer is not valid, return NULL. */
+
+static mchunkptr
+internal_function
+mem2chunk_check (void *mem, unsigned char **magic_p)
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T sz, c;
+  unsigned char magic;
+
+  if (!aligned_OK (mem))
+    return NULL;
+
+  p = mem2chunk (mem);
+  sz = chunksize (p);
+  magic = magicbyte (p);
+  if (!chunk_is_mmapped (p))
+    {
+      /* Must be a chunk in conventional heap memory. */
+      int contig = contiguous (&main_arena);
+      if ((contig &&
+           ((char *) p < mp_.sbrk_base ||
+            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
+          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
+          (!prev_inuse (p) && (p->prev_size & MALLOC_ALIGN_MASK ||
+                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
+                               next_chunk (prev_chunk (p)) != p)))
+        return NULL;
+
+      for (sz += SIZE_SZ - 1; (c = ((unsigned char *) p)[sz]) != magic; sz -= c)
+        {
+          if (c == 0 || sz < (c + 2 * SIZE_SZ))
+            return NULL;
+        }
+    }
+  else
+    {
+      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
+
+      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
+         alignment relative to the beginning of a page.  Check this
+         first. */
+      offset = (unsigned long) mem & page_mask;
+      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
+           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
+           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
+           offset < 0x2000) ||
+          !chunk_is_mmapped (p) || (p->size & PREV_INUSE) ||
+          ((((unsigned long) p - p->prev_size) & page_mask) != 0) ||
+          ((p->prev_size + sz) & page_mask) != 0)
+        return NULL;
+
+      for (sz -= 1; (c = ((unsigned char *) p)[sz]) != magic; sz -= c)
+        {
+          if (c == 0 || sz < (c + 2 * SIZE_SZ))
+            return NULL;
+        }
+    }
+  ((unsigned char *) p)[sz] ^= 0xFF;
+  if (magic_p)
+    *magic_p = (unsigned char *) p + sz;
+  return p;
+}
+
+/* Check for corruption of the top chunk, and try to recover if
+   necessary. */
+
+static int
+internal_function
+top_check (void)
+{
+  mchunkptr t = top (&main_arena);
+  char *brk, *new_brk;
+  INTERNAL_SIZE_T front_misalign, sbrk_size;
+  unsigned long pagesz = GLRO (dl_pagesize);
+
+  if (t == initial_top (&main_arena) ||
+      (!chunk_is_mmapped (t) &&
+       chunksize (t) >= MINSIZE &&
+       prev_inuse (t) &&
+       (!contiguous (&main_arena) ||
+        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
+    return 0;
+
+  malloc_printerr (check_action, "malloc: top chunk is corrupt", t,
+		   &main_arena);
+
+  /* Try to set up a new top chunk. */
+  brk = MORECORE (0);
+  front_misalign = (unsigned long) chunk2mem (brk) & MALLOC_ALIGN_MASK;
+  if (front_misalign > 0)
+    front_misalign = MALLOC_ALIGNMENT - front_misalign;
+  sbrk_size = front_misalign + mp_.top_pad + MINSIZE;
+  sbrk_size += pagesz - ((unsigned long) (brk + sbrk_size) & (pagesz - 1));
+  new_brk = (char *) (MORECORE (sbrk_size));
+  if (new_brk == (char *) (MORECORE_FAILURE))
+    {
+      __set_errno (ENOMEM);
+      return -1;
+    }
+  /* Call the `morecore' hook if necessary.  */
+  void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
+  if (hook)
+    (*hook)();
+  main_arena.system_mem = (new_brk - mp_.sbrk_base) + sbrk_size;
+
+  top (&main_arena) = (mchunkptr) (brk + front_misalign);
+  set_head (top (&main_arena), (sbrk_size - front_misalign) | PREV_INUSE);
+
+  return 0;
+}
+
+static void *
+malloc_check (size_t sz, const void *caller)
+{
+  void *victim;
+
+  if (sz + 1 == 0)
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  (void) mutex_lock (&main_arena.mutex);
+  victim = (top_check () >= 0) ? _int_malloc (&main_arena, sz + 1) : NULL;
+  (void) mutex_unlock (&main_arena.mutex);
+  return mem2mem_check (victim, sz);
+}
+
+static void
+free_check (void *mem, const void *caller)
+{
+  mchunkptr p;
+
+  if (!mem)
+    return;
+
+  (void) mutex_lock (&main_arena.mutex);
+  p = mem2chunk_check (mem, NULL);
+  if (!p)
+    {
+      (void) mutex_unlock (&main_arena.mutex);
+
+      malloc_printerr (check_action, "free(): invalid pointer", mem,
+		       &main_arena);
+      return;
+    }
+  if (chunk_is_mmapped (p))
+    {
+      (void) mutex_unlock (&main_arena.mutex);
+      munmap_chunk (p);
+      return;
+    }
+  _int_free (&main_arena, p, 1);
+  (void) mutex_unlock (&main_arena.mutex);
+}
+
+static void *
+realloc_check (void *oldmem, size_t bytes, const void *caller)
+{
+  INTERNAL_SIZE_T nb;
+  void *newmem = 0;
+  unsigned char *magic_p;
+
+  if (bytes + 1 == 0)
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+  if (oldmem == 0)
+    return malloc_check (bytes, NULL);
+
+  if (bytes == 0)
+    {
+      free_check (oldmem, NULL);
+      return NULL;
+    }
+  (void) mutex_lock (&main_arena.mutex);
+  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
+  (void) mutex_unlock (&main_arena.mutex);
+  if (!oldp)
+    {
+      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
+		       &main_arena);
+      return malloc_check (bytes, NULL);
+    }
+  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
+
+  checked_request2size (bytes + 1, nb);
+  (void) mutex_lock (&main_arena.mutex);
+
+  if (chunk_is_mmapped (oldp))
+    {
+#if HAVE_MREMAP
+      mchunkptr newp = mremap_chunk (oldp, nb);
+      if (newp)
+        newmem = chunk2mem (newp);
+      else
+#endif
+      {
+        /* Note the extra SIZE_SZ overhead. */
+        if (oldsize - SIZE_SZ >= nb)
+          newmem = oldmem; /* do nothing */
+        else
+          {
+            /* Must alloc, copy, free. */
+            if (top_check () >= 0)
+              newmem = _int_malloc (&main_arena, bytes + 1);
+            if (newmem)
+              {
+                memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ);
+                munmap_chunk (oldp);
+              }
+          }
+      }
+    }
+  else
+    {
+      if (top_check () >= 0)
+        {
+          INTERNAL_SIZE_T nb;
+          checked_request2size (bytes + 1, nb);
+          newmem = _int_realloc (&main_arena, oldp, oldsize, nb);
+        }
+    }
+
+  /* mem2chunk_check changed the magic byte in the old chunk.
+     If newmem is NULL, then the old chunk will still be used though,
+     so we need to invert that change here.  */
+  if (newmem == NULL)
+    *magic_p ^= 0xFF;
+
+  (void) mutex_unlock (&main_arena.mutex);
+
+  return mem2mem_check (newmem, bytes);
+}
+
+static void *
+memalign_check (size_t alignment, size_t bytes, const void *caller)
+{
+  void *mem;
+
+  if (alignment <= MALLOC_ALIGNMENT)
+    return malloc_check (bytes, NULL);
+
+  if (alignment < MINSIZE)
+    alignment = MINSIZE;
+
+  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
+     power of 2 and will cause overflow in the check below.  */
+  if (alignment > SIZE_MAX / 2 + 1)
+    {
+      __set_errno (EINVAL);
+      return 0;
+    }
+
+  /* Check for overflow.  */
+  if (bytes > SIZE_MAX - alignment - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
+  /* Make sure alignment is power of 2.  */
+  if (!powerof2 (alignment))
+    {
+      size_t a = MALLOC_ALIGNMENT * 2;
+      while (a < alignment)
+        a <<= 1;
+      alignment = a;
+    }
+
+  (void) mutex_lock (&main_arena.mutex);
+  mem = (top_check () >= 0) ? _int_memalign (&main_arena, alignment, bytes + 1) :
+        NULL;
+  (void) mutex_unlock (&main_arena.mutex);
+  return mem2mem_check (mem, bytes);
+}
+
+
+/* Get/set state: malloc_get_state() records the current state of all
+   malloc variables (_except_ for the actual heap contents and `hook'
+   function pointers) in a system dependent, opaque data structure.
+   This data structure is dynamically allocated and can be free()d
+   after use.  malloc_set_state() restores the state of all malloc
+   variables to the previously obtained state.  This is especially
+   useful when using this malloc as part of a shared library, and when
+   the heap contents are saved/restored via some other method.  The
+   primary example for this is GNU Emacs with its `dumping' procedure.
+   `Hook' function pointers are never saved or restored by these
+   functions, with two exceptions: If malloc checking was in use when
+   malloc_get_state() was called, then malloc_set_state() calls
+   __malloc_check_init() if possible; if malloc checking was not in
+   use in the recorded state but the user requested malloc checking,
+   then the hooks are reset to 0.  */
+
+#define MALLOC_STATE_MAGIC   0x444c4541l
+#define MALLOC_STATE_VERSION (0 * 0x100l + 4l) /* major*0x100 + minor */
+
+struct malloc_save_state
+{
+  long magic;
+  long version;
+  mbinptr av[NBINS * 2 + 2];
+  char *sbrk_base;
+  int sbrked_mem_bytes;
+  unsigned long trim_threshold;
+  unsigned long top_pad;
+  unsigned int n_mmaps_max;
+  unsigned long mmap_threshold;
+  int check_action;
+  unsigned long max_sbrked_mem;
+  unsigned long max_total_mem;
+  unsigned int n_mmaps;
+  unsigned int max_n_mmaps;
+  unsigned long mmapped_mem;
+  unsigned long max_mmapped_mem;
+  int using_malloc_checking;
+  unsigned long max_fast;
+  unsigned long arena_test;
+  unsigned long arena_max;
+  unsigned long narenas;
+};
+
+void *
+__malloc_get_state (void)
+{
+  struct malloc_save_state *ms;
+  int i;
+  mbinptr b;
+
+  ms = (struct malloc_save_state *) __libc_malloc (sizeof (*ms));
+  if (!ms)
+    return 0;
+
+  (void) mutex_lock (&main_arena.mutex);
+  malloc_consolidate (&main_arena);
+  ms->magic = MALLOC_STATE_MAGIC;
+  ms->version = MALLOC_STATE_VERSION;
+  ms->av[0] = 0;
+  ms->av[1] = 0; /* used to be binblocks, now no longer used */
+  ms->av[2] = top (&main_arena);
+  ms->av[3] = 0; /* used to be undefined */
+  for (i = 1; i < NBINS; i++)
+    {
+      b = bin_at (&main_arena, i);
+      if (first (b) == b)
+        ms->av[2 * i + 2] = ms->av[2 * i + 3] = 0; /* empty bin */
+      else
+        {
+          ms->av[2 * i + 2] = first (b);
+          ms->av[2 * i + 3] = last (b);
+        }
+    }
+  ms->sbrk_base = mp_.sbrk_base;
+  ms->sbrked_mem_bytes = main_arena.system_mem;
+  ms->trim_threshold = mp_.trim_threshold;
+  ms->top_pad = mp_.top_pad;
+  ms->n_mmaps_max = mp_.n_mmaps_max;
+  ms->mmap_threshold = mp_.mmap_threshold;
+  ms->check_action = check_action;
+  ms->max_sbrked_mem = main_arena.max_system_mem;
+  ms->max_total_mem = 0;
+  ms->n_mmaps = mp_.n_mmaps;
+  ms->max_n_mmaps = mp_.max_n_mmaps;
+  ms->mmapped_mem = mp_.mmapped_mem;
+  ms->max_mmapped_mem = mp_.max_mmapped_mem;
+  ms->using_malloc_checking = using_malloc_checking;
+  ms->max_fast = get_max_fast ();
+  ms->arena_test = mp_.arena_test;
+  ms->arena_max = mp_.arena_max;
+  ms->narenas = narenas;
+  (void) mutex_unlock (&main_arena.mutex);
+  return (void *) ms;
+}
+
+int
+__malloc_set_state (void *msptr)
+{
+  struct malloc_save_state *ms = (struct malloc_save_state *) msptr;
+  size_t i;
+  mbinptr b;
+
+  disallow_malloc_check = 1;
+  ptmalloc_init ();
+  if (ms->magic != MALLOC_STATE_MAGIC)
+    return -1;
+
+  /* Must fail if the major version is too high. */
+  if ((ms->version & ~0xffl) > (MALLOC_STATE_VERSION & ~0xffl))
+    return -2;
+
+  (void) mutex_lock (&main_arena.mutex);
+  /* There are no fastchunks.  */
+  clear_fastchunks (&main_arena);
+  if (ms->version >= 4)
+    set_max_fast (ms->max_fast);
+  else
+    set_max_fast (64);  /* 64 used to be the value we always used.  */
+  for (i = 0; i < NFASTBINS; ++i)
+    fastbin (&main_arena, i) = 0;
+  for (i = 0; i < BINMAPSIZE; ++i)
+    main_arena.binmap[i] = 0;
+  top (&main_arena) = ms->av[2];
+  main_arena.last_remainder = 0;
+  for (i = 1; i < NBINS; i++)
+    {
+      b = bin_at (&main_arena, i);
+      if (ms->av[2 * i + 2] == 0)
+        {
+          assert (ms->av[2 * i + 3] == 0);
+          first (b) = last (b) = b;
+        }
+      else
+        {
+          if (ms->version >= 3 &&
+              (i < NSMALLBINS || (largebin_index (chunksize (ms->av[2 * i + 2])) == i &&
+                                  largebin_index (chunksize (ms->av[2 * i + 3])) == i)))
+            {
+              first (b) = ms->av[2 * i + 2];
+              last (b) = ms->av[2 * i + 3];
+              /* Make sure the links to the bins within the heap are correct.  */
+              first (b)->bk = b;
+              last (b)->fd = b;
+              /* Set bit in binblocks.  */
+              mark_bin (&main_arena, i);
+            }
+          else
+            {
+              /* Oops, index computation from chunksize must have changed.
+                 Link the whole list into unsorted_chunks.  */
+              first (b) = last (b) = b;
+              b = unsorted_chunks (&main_arena);
+              ms->av[2 * i + 2]->bk = b;
+              ms->av[2 * i + 3]->fd = b->fd;
+              b->fd->bk = ms->av[2 * i + 3];
+              b->fd = ms->av[2 * i + 2];
+            }
+        }
+    }
+  if (ms->version < 3)
+    {
+      /* Clear fd_nextsize and bk_nextsize fields.  */
+      b = unsorted_chunks (&main_arena)->fd;
+      while (b != unsorted_chunks (&main_arena))
+        {
+          if (!in_smallbin_range (chunksize (b)))
+            {
+              b->fd_nextsize = NULL;
+              b->bk_nextsize = NULL;
+            }
+          b = b->fd;
+        }
+    }
+  mp_.sbrk_base = ms->sbrk_base;
+  main_arena.system_mem = ms->sbrked_mem_bytes;
+  mp_.trim_threshold = ms->trim_threshold;
+  mp_.top_pad = ms->top_pad;
+  mp_.n_mmaps_max = ms->n_mmaps_max;
+  mp_.mmap_threshold = ms->mmap_threshold;
+  check_action = ms->check_action;
+  main_arena.max_system_mem = ms->max_sbrked_mem;
+  mp_.n_mmaps = ms->n_mmaps;
+  mp_.max_n_mmaps = ms->max_n_mmaps;
+  mp_.mmapped_mem = ms->mmapped_mem;
+  mp_.max_mmapped_mem = ms->max_mmapped_mem;
+  /* add version-dependent code here */
+  if (ms->version >= 1)
+    {
+      /* Check whether it is safe to enable malloc checking, or whether
+         it is necessary to disable it.  */
+      if (ms->using_malloc_checking && !using_malloc_checking &&
+          !disallow_malloc_check)
+        __malloc_check_init ();
+      else if (!ms->using_malloc_checking && using_malloc_checking)
+        {
+          __malloc_hook = NULL;
+          __free_hook = NULL;
+          __realloc_hook = NULL;
+          __memalign_hook = NULL;
+          using_malloc_checking = 0;
+        }
+    }
+  if (ms->version >= 4)
+    {
+      mp_.arena_test = ms->arena_test;
+      mp_.arena_max = ms->arena_max;
+      narenas = ms->narenas;
+    }
+  check_malloc_state (&main_arena);
+
+  (void) mutex_unlock (&main_arena.mutex);
+  return 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/malloc.c b/ap/libc/glibc/glibc-2.23/malloc/malloc.c
new file mode 100644
index 0000000..d20d595
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/malloc.c
@@ -0,0 +1,5249 @@
+/* Malloc implementation for multiple threads without lock contention.
+   Copyright (C) 1996-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Wolfram Gloger <wg@malloc.de>
+   and Doug Lea <dl@cs.oswego.edu>, 2001.
+
+   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 <http://www.gnu.org/licenses/>.  */
+
+/*
+  This is a version (aka ptmalloc2) of malloc/free/realloc written by
+  Doug Lea and adapted to multiple threads/arenas by Wolfram Gloger.
+
+  There have been substantial changes made after the integration into
+  glibc in all parts of the code.  Do not look for much commonality
+  with the ptmalloc2 version.
+
+* Version ptmalloc2-20011215
+  based on:
+  VERSION 2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+
+* Quickstart
+
+  In order to compile this implementation, a Makefile is provided with
+  the ptmalloc2 distribution, which has pre-defined targets for some
+  popular systems (e.g. "make posix" for Posix threads).  All that is
+  typically required with regard to compiler flags is the selection of
+  the thread package via defining one out of USE_PTHREADS, USE_THR or
+  USE_SPROC.  Check the thread-m.h file for what effects this has.
+  Many/most systems will additionally require USE_TSD_DATA_HACK to be
+  defined, so this is the default for "make posix".
+
+* Why use this malloc?
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and tunable.
+  Consistent balance across these factors results in a good general-purpose
+  allocator for malloc-intensive programs.
+
+  The main properties of the algorithms are:
+  * For large (>= 512 bytes) requests, it is a pure best-fit allocator,
+    with ties normally decided via FIFO (i.e. least recently used).
+  * For small (<= 64 bytes by default) requests, it is a caching
+    allocator, that maintains pools of quickly recycled chunks.
+  * In between, and for combinations of large and small requests, it does
+    the best it can trying to meet both goals at once.
+  * For very large requests (>= 128KB by default), it relies on system
+    memory mapping facilities, if supported.
+
+  For a longer but slightly out of date high-level description, see
+     http://gee.cs.oswego.edu/dl/html/malloc.html
+
+  You may already by default be using a C library containing a malloc
+  that is  based on some version of this malloc (for example in
+  linux). You might still want to use the one in this file in order to
+  customize settings or to avoid overheads associated with library
+  versions.
+
+* Contents, described in more detail in "description of public routines" below.
+
+  Standard (ANSI/SVID/...)  functions:
+    malloc(size_t n);
+    calloc(size_t n_elements, size_t element_size);
+    free(void* p);
+    realloc(void* p, size_t n);
+    memalign(size_t alignment, size_t n);
+    valloc(size_t n);
+    mallinfo()
+    mallopt(int parameter_number, int parameter_value)
+
+  Additional functions:
+    independent_calloc(size_t n_elements, size_t size, void* chunks[]);
+    independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+    pvalloc(size_t n);
+    cfree(void* p);
+    malloc_trim(size_t pad);
+    malloc_usable_size(void* p);
+    malloc_stats();
+
+* Vital statistics:
+
+  Supported pointer representation:       4 or 8 bytes
+  Supported size_t  representation:       4 or 8 bytes
+       Note that size_t is allowed to be 4 bytes even if pointers are 8.
+       You can adjust this by defining INTERNAL_SIZE_T
+
+  Alignment:                              2 * sizeof(size_t) (default)
+       (i.e., 8 byte alignment with 4byte size_t). This suffices for
+       nearly all current machines and C compilers. However, you can
+       define MALLOC_ALIGNMENT to be wider than this if necessary.
+
+  Minimum overhead per allocated chunk:   4 or 8 bytes
+       Each malloced chunk has a hidden word of overhead holding size
+       and status information.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including 4 overhead)
+			  8-byte ptrs:  24/32 bytes (including, 4/8 overhead)
+
+       When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte
+       ptrs but 4 byte size) or 24 (for 8/8) additional bytes are
+       needed; 4 (8) for a trailing size field and 8 (16) bytes for
+       free list pointers. Thus, the minimum allocatable size is
+       16/24/32 bytes.
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+
+       The maximum overhead wastage (i.e., number of extra bytes
+       allocated than were requested in malloc) is less than or equal
+       to the minimum size, except for requests >= mmap_threshold that
+       are serviced via mmap(), where the worst case wastage is 2 *
+       sizeof(size_t) bytes plus the remainder from a system page (the
+       minimal mmap unit); typically 4096 or 8192 bytes.
+
+  Maximum allocated size:  4-byte size_t: 2^32 minus about two pages
+			   8-byte size_t: 2^64 minus about two pages
+
+       It is assumed that (possibly signed) size_t values suffice to
+       represent chunk sizes. `Possibly signed' is due to the fact
+       that `size_t' may be defined on a system as either a signed or
+       an unsigned type. The ISO C standard says that it must be
+       unsigned, but a few systems are known not to adhere to this.
+       Additionally, even when size_t is unsigned, sbrk (which is by
+       default used to obtain memory from system) accepts signed
+       arguments, and may not be able to handle size_t-wide arguments
+       with negative sign bit.  Generally, values that would
+       appear as negative after accounting for overhead and alignment
+       are supported only via mmap(), which does not have this
+       limitation.
+
+       Requests for sizes outside the allowed range will perform an optional
+       failure action and then return null. (Requests may also
+       also fail because a system is out of memory.)
+
+  Thread-safety: thread-safe
+
+  Compliance: I believe it is compliant with the 1997 Single Unix Specification
+       Also SVID/XPG, ANSI C, and probably others as well.
+
+* Synopsis of compile-time options:
+
+    People have reported using previous versions of this malloc on all
+    versions of Unix, sometimes by tweaking some of the defines
+    below. It has been tested most extensively on Solaris and Linux.
+    People also report using it in stand-alone embedded systems.
+
+    The implementation is in straight, hand-tuned ANSI C.  It is not
+    at all modular. (Sorry!)  It uses a lot of macros.  To be at all
+    usable, this code should be compiled using an optimizing compiler
+    (for example gcc -O3) that can simplify expressions and control
+    paths. (FAQ: some macros import variables as arguments rather than
+    declare locals because people reported that some debuggers
+    otherwise get confused.)
+
+    OPTION                     DEFAULT VALUE
+
+    Compilation Environment options:
+
+    HAVE_MREMAP                0
+
+    Changing default word sizes:
+
+    INTERNAL_SIZE_T            size_t
+    MALLOC_ALIGNMENT           MAX (2 * sizeof(INTERNAL_SIZE_T),
+				    __alignof__ (long double))
+
+    Configuration and functionality options:
+
+    USE_PUBLIC_MALLOC_WRAPPERS NOT defined
+    USE_MALLOC_LOCK            NOT defined
+    MALLOC_DEBUG               NOT defined
+    REALLOC_ZERO_BYTES_FREES   1
+    TRIM_FASTBINS              0
+
+    Options for customizing MORECORE:
+
+    MORECORE                   sbrk
+    MORECORE_FAILURE           -1
+    MORECORE_CONTIGUOUS        1
+    MORECORE_CANNOT_TRIM       NOT defined
+    MORECORE_CLEARS            1
+    MMAP_AS_MORECORE_SIZE      (1024 * 1024)
+
+    Tuning options that are also dynamically changeable via mallopt:
+
+    DEFAULT_MXFAST             64 (for 32bit), 128 (for 64bit)
+    DEFAULT_TRIM_THRESHOLD     128 * 1024
+    DEFAULT_TOP_PAD            0
+    DEFAULT_MMAP_THRESHOLD     128 * 1024
+    DEFAULT_MMAP_MAX           65536
+
+    There are several other #defined constants and macros that you
+    probably don't want to touch unless you are extending or adapting malloc.  */
+
+/*
+  void* is the pointer type that malloc should say it returns
+*/
+
+#ifndef void
+#define void      void
+#endif /*void*/
+
+#include <stddef.h>   /* for size_t */
+#include <stdlib.h>   /* for getenv(), abort() */
+#include <unistd.h>   /* for __libc_enable_secure */
+
+#include <malloc-machine.h>
+#include <malloc-sysdep.h>
+
+#include <atomic.h>
+#include <_itoa.h>
+#include <bits/wordsize.h>
+#include <sys/sysinfo.h>
+
+#include <ldsodefs.h>
+
+#include <unistd.h>
+#include <stdio.h>    /* needed for malloc_stats */
+#include <errno.h>
+
+#include <shlib-compat.h>
+
+/* For uintptr_t.  */
+#include <stdint.h>
+
+/* For va_arg, va_start, va_end.  */
+#include <stdarg.h>
+
+/* For MIN, MAX, powerof2.  */
+#include <sys/param.h>
+
+/* For ALIGN_UP et. al.  */
+#include <libc-internal.h>
+
+
+/*
+  Debugging:
+
+  Because freed chunks may be overwritten with bookkeeping fields, this
+  malloc will often die when freed memory is overwritten by user
+  programs.  This can be very effective (albeit in an annoying way)
+  in helping track down dangling pointers.
+
+  If you compile with -DMALLOC_DEBUG, a number of assertion checks are
+  enabled that will catch more memory errors. You probably won't be
+  able to make much sense of the actual assertion errors, but they
+  should help you locate incorrectly overwritten memory.  The checking
+  is fairly extensive, and will slow down execution
+  noticeably. Calling malloc_stats or mallinfo with MALLOC_DEBUG set
+  will attempt to check every non-mmapped allocated and free chunk in
+  the course of computing the summmaries. (By nature, mmapped regions
+  cannot be checked very much automatically.)
+
+  Setting MALLOC_DEBUG may also be helpful if you are trying to modify
+  this code. The assertions in the check routines spell out in more
+  detail the assumptions and invariants underlying the algorithms.
+
+  Setting MALLOC_DEBUG does NOT provide an automated mechanism for
+  checking that all accesses to malloced memory stay within their
+  bounds. However, there are several add-ons and adaptations of this
+  or other mallocs available that do this.
+*/
+
+#ifndef MALLOC_DEBUG
+#define MALLOC_DEBUG 0
+#endif
+
+#ifdef NDEBUG
+# define assert(expr) ((void) 0)
+#else
+# define assert(expr) \
+  ((expr)								      \
+   ? ((void) 0)								      \
+   : __malloc_assert (#expr, __FILE__, __LINE__, __func__))
+
+extern const char *__progname;
+
+static void
+__malloc_assert (const char *assertion, const char *file, unsigned int line,
+		 const char *function)
+{
+  (void) __fxprintf (NULL, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
+		     __progname, __progname[0] ? ": " : "",
+		     file, line,
+		     function ? function : "", function ? ": " : "",
+		     assertion);
+  fflush (stderr);
+  abort ();
+}
+#endif
+
+
+/*
+  INTERNAL_SIZE_T is the word-size used for internal bookkeeping
+  of chunk sizes.
+
+  The default version is the same as size_t.
+
+  While not strictly necessary, it is best to define this as an
+  unsigned type, even if size_t is a signed type. This may avoid some
+  artificial size limitations on some systems.
+
+  On a 64-bit machine, you may be able to reduce malloc overhead by
+  defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' at the
+  expense of not being able to handle more than 2^32 of malloced
+  space. If this limitation is acceptable, you are encouraged to set
+  this unless you are on a platform requiring 16byte alignments. In
+  this case the alignment requirements turn out to negate any
+  potential advantages of decreasing size_t word size.
+
+  Implementors: Beware of the possible combinations of:
+     - INTERNAL_SIZE_T might be signed or unsigned, might be 32 or 64 bits,
+       and might be the same width as int or as long
+     - size_t might have different width and signedness as INTERNAL_SIZE_T
+     - int and long might be 32 or 64 bits, and might be the same width
+  To deal with this, most comparisons and difference computations
+  among INTERNAL_SIZE_Ts should cast them to unsigned long, being
+  aware of the fact that casting an unsigned int to a wider long does
+  not sign-extend. (This also makes checking for negative numbers
+  awkward.) Some of these casts result in harmless compiler warnings
+  on some systems.
+*/
+
+#ifndef INTERNAL_SIZE_T
+#define INTERNAL_SIZE_T size_t
+#endif
+
+/* The corresponding word size */
+#define SIZE_SZ                (sizeof(INTERNAL_SIZE_T))
+
+
+/*
+  MALLOC_ALIGNMENT is the minimum alignment for malloc'ed chunks.
+  It must be a power of two at least 2 * SIZE_SZ, even on machines
+  for which smaller alignments would suffice. It may be defined as
+  larger than this though. Note however that code and data structures
+  are optimized for the case of 8-byte alignment.
+*/
+
+
+#ifndef MALLOC_ALIGNMENT
+# if !SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_16)
+/* This is the correct definition when there is no past ABI to constrain it.
+
+   Among configurations with a past ABI constraint, it differs from
+   2*SIZE_SZ only on powerpc32.  For the time being, changing this is
+   causing more compatibility problems due to malloc_get_state and
+   malloc_set_state than will returning blocks not adequately aligned for
+   long double objects under -mlong-double-128.  */
+
+#  define MALLOC_ALIGNMENT       (2 *SIZE_SZ < __alignof__ (long double)      \
+                                  ? __alignof__ (long double) : 2 *SIZE_SZ)
+# else
+#  define MALLOC_ALIGNMENT       (2 *SIZE_SZ)
+# endif
+#endif
+
+/* The corresponding bit mask value */
+#define MALLOC_ALIGN_MASK      (MALLOC_ALIGNMENT - 1)
+
+
+
+/*
+  REALLOC_ZERO_BYTES_FREES should be set if a call to
+  realloc with zero bytes should be the same as a call to free.
+  This is required by the C standard. Otherwise, since this malloc
+  returns a unique pointer for malloc(0), so does realloc(p, 0).
+*/
+
+#ifndef REALLOC_ZERO_BYTES_FREES
+#define REALLOC_ZERO_BYTES_FREES 1
+#endif
+
+/*
+  TRIM_FASTBINS controls whether free() of a very small chunk can
+  immediately lead to trimming. Setting to true (1) can reduce memory
+  footprint, but will almost always slow down programs that use a lot
+  of small chunks.
+
+  Define this only if you are willing to give up some speed to more
+  aggressively reduce system-level memory footprint when releasing
+  memory in programs that use many small chunks.  You can get
+  essentially the same effect by setting MXFAST to 0, but this can
+  lead to even greater slowdowns in programs using many small chunks.
+  TRIM_FASTBINS is an in-between compile-time option, that disables
+  only those chunks bordering topmost memory from being placed in
+  fastbins.
+*/
+
+#ifndef TRIM_FASTBINS
+#define TRIM_FASTBINS  0
+#endif
+
+
+/* Definition for getting more memory from the OS.  */
+#define MORECORE         (*__morecore)
+#define MORECORE_FAILURE 0
+void * __default_morecore (ptrdiff_t);
+void *(*__morecore)(ptrdiff_t) = __default_morecore;
+
+
+#include <string.h>
+
+/*
+  MORECORE-related declarations. By default, rely on sbrk
+*/
+
+
+/*
+  MORECORE is the name of the routine to call to obtain more memory
+  from the system.  See below for general guidance on writing
+  alternative MORECORE functions, as well as a version for WIN32 and a
+  sample version for pre-OSX macos.
+*/
+
+#ifndef MORECORE
+#define MORECORE sbrk
+#endif
+
+/*
+  MORECORE_FAILURE is the value returned upon failure of MORECORE
+  as well as mmap. Since it cannot be an otherwise valid memory address,
+  and must reflect values of standard sys calls, you probably ought not
+  try to redefine it.
+*/
+
+#ifndef MORECORE_FAILURE
+#define MORECORE_FAILURE (-1)
+#endif
+
+/*
+  If MORECORE_CONTIGUOUS is true, take advantage of fact that
+  consecutive calls to MORECORE with positive arguments always return
+  contiguous increasing addresses.  This is true of unix sbrk.  Even
+  if not defined, when regions happen to be contiguous, malloc will
+  permit allocations spanning regions obtained from different
+  calls. But defining this when applicable enables some stronger
+  consistency checks and space efficiencies.
+*/
+
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif
+
+/*
+  Define MORECORE_CANNOT_TRIM if your version of MORECORE
+  cannot release space back to the system when given negative
+  arguments. This is generally necessary only if you are using
+  a hand-crafted MORECORE function that cannot handle negative arguments.
+*/
+
+/* #define MORECORE_CANNOT_TRIM */
+
+/*  MORECORE_CLEARS           (default 1)
+     The degree to which the routine mapped to MORECORE zeroes out
+     memory: never (0), only for newly allocated space (1) or always
+     (2).  The distinction between (1) and (2) is necessary because on
+     some systems, if the application first decrements and then
+     increments the break value, the contents of the reallocated space
+     are unspecified.
+ */
+
+#ifndef MORECORE_CLEARS
+# define MORECORE_CLEARS 1
+#endif
+
+
+/*
+   MMAP_AS_MORECORE_SIZE is the minimum mmap size argument to use if
+   sbrk fails, and mmap is used as a backup.  The value must be a
+   multiple of page size.  This backup strategy generally applies only
+   when systems have "holes" in address space, so sbrk cannot perform
+   contiguous expansion, but there is still space available on system.
+   On systems for which this is known to be useful (i.e. most linux
+   kernels), this occurs only when programs allocate huge amounts of
+   memory.  Between this, and the fact that mmap regions tend to be
+   limited, the size should be large, to avoid too many mmap calls and
+   thus avoid running out of kernel resources.  */
+
+#ifndef MMAP_AS_MORECORE_SIZE
+#define MMAP_AS_MORECORE_SIZE (1024 * 1024)
+#endif
+
+/*
+  Define HAVE_MREMAP to make realloc() use mremap() to re-allocate
+  large blocks.
+*/
+
+#ifndef HAVE_MREMAP
+#define HAVE_MREMAP 0
+#endif
+
+
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any SVID/XPG compliant system that has
+  a /usr/include/malloc.h defining struct mallinfo. (If you'd like to
+  install such a thing yourself, cut out the preliminary declarations
+  as described above and below and save them in a malloc.h file. But
+  there's no compelling reason to bother to do this.)
+
+  The main declaration needed is the mallinfo struct that is returned
+  (by-copy) by mallinfo().  The SVID/XPG malloinfo struct contains a
+  bunch of fields that are not even meaningful in this version of
+  malloc.  These fields are are instead filled by mallinfo() with
+  other numbers that might be of interest.
+*/
+
+
+/* ---------- description of public routines ------------ */
+
+/*
+  malloc(size_t n)
+  Returns a pointer to a newly allocated chunk of at least n bytes, or null
+  if no space is available. Additionally, on failure, errno is
+  set to ENOMEM on ANSI C systems.
+
+  If n is zero, malloc returns a minumum-sized chunk. (The minimum
+  size is 16 bytes on most 32bit systems, and 24 or 32 bytes on 64bit
+  systems.)  On most systems, size_t is an unsigned type, so calls
+  with negative arguments are interpreted as requests for huge amounts
+  of space, which will often fail. The maximum supported value of n
+  differs across systems, but is in all cases less than the maximum
+  representable value of a size_t.
+*/
+void*  __libc_malloc(size_t);
+libc_hidden_proto (__libc_malloc)
+
+/*
+  free(void* p)
+  Releases the chunk of memory pointed to by p, that had been previously
+  allocated using malloc or a related routine such as realloc.
+  It has no effect if p is null. It can have arbitrary (i.e., bad!)
+  effects if p has already been freed.
+
+  Unless disabled (using mallopt), freeing very large spaces will
+  when possible, automatically trigger operations that give
+  back unused memory to the system, thus reducing program footprint.
+*/
+void     __libc_free(void*);
+libc_hidden_proto (__libc_free)
+
+/*
+  calloc(size_t n_elements, size_t element_size);
+  Returns a pointer to n_elements * element_size bytes, with all locations
+  set to zero.
+*/
+void*  __libc_calloc(size_t, size_t);
+
+/*
+  realloc(void* p, size_t n)
+  Returns a pointer to a chunk of size n that contains the same data
+  as does chunk p up to the minimum of (n, p's size) bytes, or null
+  if no space is available.
+
+  The returned pointer may or may not be the same as p. The algorithm
+  prefers extending p when possible, otherwise it employs the
+  equivalent of a malloc-copy-free sequence.
+
+  If p is null, realloc is equivalent to malloc.
+
+  If space is not available, realloc returns null, errno is set (if on
+  ANSI) and p is NOT freed.
+
+  if n is for fewer bytes than already held by p, the newly unused
+  space is lopped off and freed if possible.  Unless the #define
+  REALLOC_ZERO_BYTES_FREES is set, realloc with a size argument of
+  zero (re)allocates a minimum-sized chunk.
+
+  Large chunks that were internally obtained via mmap will always
+  be reallocated using malloc-copy-free sequences unless
+  the system supports MREMAP (currently only linux).
+
+  The old unix realloc convention of allowing the last-free'd chunk
+  to be used as an argument to realloc is not supported.
+*/
+void*  __libc_realloc(void*, size_t);
+libc_hidden_proto (__libc_realloc)
+
+/*
+  memalign(size_t alignment, size_t n);
+  Returns a pointer to a newly allocated chunk of n bytes, aligned
+  in accord with the alignment argument.
+
+  The alignment argument should be a power of two. If the argument is
+  not a power of two, the nearest greater power is used.
+  8-byte alignment is guaranteed by normal malloc calls, so don't
+  bother calling memalign with an argument of 8 or less.
+
+  Overreliance on memalign is a sure way to fragment space.
+*/
+void*  __libc_memalign(size_t, size_t);
+libc_hidden_proto (__libc_memalign)
+
+/*
+  valloc(size_t n);
+  Equivalent to memalign(pagesize, n), where pagesize is the page
+  size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void*  __libc_valloc(size_t);
+
+
+
+/*
+  mallopt(int parameter_number, int parameter_value)
+  Sets tunable parameters The format is to provide a
+  (parameter-number, parameter-value) pair.  mallopt then sets the
+  corresponding parameter to the argument value if it can (i.e., so
+  long as the value is meaningful), and returns 1 if successful else
+  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
+  normally defined in malloc.h.  Only one of these (M_MXFAST) is used
+  in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply,
+  so setting them has no effect. But this malloc also supports four
+  other options in mallopt. See below for details.  Briefly, supported
+  parameters are as follows (listed defaults are for "typical"
+  configurations).
+
+  Symbol            param #   default    allowed param values
+  M_MXFAST          1         64         0-80  (0 disables fastbins)
+  M_TRIM_THRESHOLD -1         128*1024   any   (-1U disables trimming)
+  M_TOP_PAD        -2         0          any
+  M_MMAP_THRESHOLD -3         128*1024   any   (or 0 if no MMAP support)
+  M_MMAP_MAX       -4         65536      any   (0 disables use of mmap)
+*/
+int      __libc_mallopt(int, int);
+libc_hidden_proto (__libc_mallopt)
+
+
+/*
+  mallinfo()
+  Returns (by copy) a struct containing various summary statistics:
+
+  arena:     current total non-mmapped bytes allocated from system
+  ordblks:   the number of free chunks
+  smblks:    the number of fastbin blocks (i.e., small chunks that
+	       have been freed but not use resused or consolidated)
+  hblks:     current number of mmapped regions
+  hblkhd:    total bytes held in mmapped regions
+  usmblks:   the maximum total allocated space. This will be greater
+		than current total if trimming has occurred.
+  fsmblks:   total bytes held in fastbin blocks
+  uordblks:  current total allocated space (normal or mmapped)
+  fordblks:  total free space
+  keepcost:  the maximum number of bytes that could ideally be released
+	       back to system via malloc_trim. ("ideally" means that
+	       it ignores page restrictions etc.)
+
+  Because these fields are ints, but internal bookkeeping may
+  be kept as longs, the reported values may wrap around zero and
+  thus be inaccurate.
+*/
+struct mallinfo __libc_mallinfo(void);
+
+
+/*
+  pvalloc(size_t n);
+  Equivalent to valloc(minimum-page-that-holds(n)), that is,
+  round up n to nearest pagesize.
+ */
+void*  __libc_pvalloc(size_t);
+
+/*
+  malloc_trim(size_t pad);
+
+  If possible, gives memory back to the system (via negative
+  arguments to sbrk) if there is unused memory at the `high' end of
+  the malloc pool. You can call this after freeing large blocks of
+  memory to potentially reduce the system-level memory requirements
+  of a program. However, it cannot guarantee to reduce memory. Under
+  some allocation patterns, some large free blocks of memory will be
+  locked between two used chunks, so they cannot be given back to
+  the system.
+
+  The `pad' argument to malloc_trim represents the amount of free
+  trailing space to leave untrimmed. If this argument is zero,
+  only the minimum amount of memory to maintain internal data
+  structures will be left (one page or less). Non-zero arguments
+  can be supplied to maintain enough trailing space to service
+  future expected allocations without having to re-obtain memory
+  from the system.
+
+  Malloc_trim returns 1 if it actually released any memory, else 0.
+  On systems that do not support "negative sbrks", it will always
+  return 0.
+*/
+int      __malloc_trim(size_t);
+
+/*
+  malloc_usable_size(void* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. malloc_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = malloc(n);
+  assert(malloc_usable_size(p) >= 256);
+
+*/
+size_t   __malloc_usable_size(void*);
+
+/*
+  malloc_stats();
+  Prints on stderr the amount of space obtained from the system (both
+  via sbrk and mmap), the maximum amount (which may be more than
+  current if malloc_trim and/or munmap got called), and the current
+  number of bytes allocated via malloc (or realloc, etc) but not yet
+  freed. Note that this is the number of bytes allocated, not the
+  number requested. It will be larger than the number requested
+  because of alignment and bookkeeping overhead. Because it includes
+  alignment wastage as being in use, this figure may be greater than
+  zero even when no user-level chunks are allocated.
+
+  The reported current and maximum system memory can be inaccurate if
+  a program makes other calls to system memory allocation functions
+  (normally sbrk) outside of malloc.
+
+  malloc_stats prints only the most commonly interesting statistics.
+  More information can be obtained by calling mallinfo.
+
+*/
+void     __malloc_stats(void);
+
+/*
+  malloc_get_state(void);
+
+  Returns the state of all malloc variables in an opaque data
+  structure.
+*/
+void*  __malloc_get_state(void);
+
+/*
+  malloc_set_state(void* state);
+
+  Restore the state of all malloc variables from data obtained with
+  malloc_get_state().
+*/
+int      __malloc_set_state(void*);
+
+/*
+  posix_memalign(void **memptr, size_t alignment, size_t size);
+
+  POSIX wrapper like memalign(), checking for validity of size.
+*/
+int      __posix_memalign(void **, size_t, size_t);
+
+/* mallopt tuning options */
+
+/*
+  M_MXFAST is the maximum request size used for "fastbins", special bins
+  that hold returned chunks without consolidating their spaces. This
+  enables future requests for chunks of the same size to be handled
+  very quickly, but can increase fragmentation, and thus increase the
+  overall memory footprint of a program.
+
+  This malloc manages fastbins very conservatively yet still
+  efficiently, so fragmentation is rarely a problem for values less
+  than or equal to the default.  The maximum supported value of MXFAST
+  is 80. You wouldn't want it any higher than this anyway.  Fastbins
+  are designed especially for use with many small structs, objects or
+  strings -- the default handles structs/objects/arrays with sizes up
+  to 8 4byte fields, or small strings representing words, tokens,
+  etc. Using fastbins for larger objects normally worsens
+  fragmentation without improving speed.
+
+  M_MXFAST is set in REQUEST size units. It is internally used in
+  chunksize units, which adds padding and alignment.  You can reduce
+  M_MXFAST to 0 to disable all use of fastbins.  This causes the malloc
+  algorithm to be a closer approximation of fifo-best-fit in all cases,
+  not just for larger requests, but will generally cause it to be
+  slower.
+*/
+
+
+/* M_MXFAST is a standard SVID/XPG tuning option, usually listed in malloc.h */
+#ifndef M_MXFAST
+#define M_MXFAST            1
+#endif
+
+#ifndef DEFAULT_MXFAST
+#define DEFAULT_MXFAST     (64 * SIZE_SZ / 4)
+#endif
+
+
+/*
+  M_TRIM_THRESHOLD is the maximum amount of unused top-most memory
+  to keep before releasing via malloc_trim in free().
+
+  Automatic trimming is mainly useful in long-lived programs.
+  Because trimming via sbrk can be slow on some systems, and can
+  sometimes be wasteful (in cases where programs immediately
+  afterward allocate more large chunks) the value should be high
+  enough so that your overall system performance would improve by
+  releasing this much memory.
+
+  The trim threshold and the mmap control parameters (see below)
+  can be traded off with one another. Trimming and mmapping are
+  two different ways of releasing unused memory back to the
+  system. Between these two, it is often possible to keep
+  system-level demands of a long-lived program down to a bare
+  minimum. For example, in one test suite of sessions measuring
+  the XF86 X server on Linux, using a trim threshold of 128K and a
+  mmap threshold of 192K led to near-minimal long term resource
+  consumption.
+
+  If you are using this malloc in a long-lived program, it should
+  pay to experiment with these values.  As a rough guide, you
+  might set to a value close to the average size of a process
+  (program) running on your system.  Releasing this much memory
+  would allow such a process to run in memory.  Generally, it's
+  worth it to tune for trimming rather tham memory mapping when a
+  program undergoes phases where several large chunks are
+  allocated and released in ways that can reuse each other's
+  storage, perhaps mixed with phases where there are no such
+  chunks at all.  And in well-behaved long-lived programs,
+  controlling release of large blocks via trimming versus mapping
+  is usually faster.
+
+  However, in most programs, these parameters serve mainly as
+  protection against the system-level effects of carrying around
+  massive amounts of unneeded memory. Since frequent calls to
+  sbrk, mmap, and munmap otherwise degrade performance, the default
+  parameters are set to relatively high values that serve only as
+  safeguards.
+
+  The trim value It must be greater than page size to have any useful
+  effect.  To disable trimming completely, you can set to
+  (unsigned long)(-1)
+
+  Trim settings interact with fastbin (MXFAST) settings: Unless
+  TRIM_FASTBINS is defined, automatic trimming never takes place upon
+  freeing a chunk with size less than or equal to MXFAST. Trimming is
+  instead delayed until subsequent freeing of larger chunks. However,
+  you can still force an attempted trim by calling malloc_trim.
+
+  Also, trimming is not generally possible in cases where
+  the main arena is obtained via mmap.
+
+  Note that the trick some people use of mallocing a huge space and
+  then freeing it at program startup, in an attempt to reserve system
+  memory, doesn't have the intended effect under automatic trimming,
+  since that memory will immediately be returned to the system.
+*/
+
+#define M_TRIM_THRESHOLD       -1
+
+#ifndef DEFAULT_TRIM_THRESHOLD
+#define DEFAULT_TRIM_THRESHOLD (128 * 1024)
+#endif
+
+/*
+  M_TOP_PAD is the amount of extra `padding' space to allocate or
+  retain whenever sbrk is called. It is used in two ways internally:
+
+  * When sbrk is called to extend the top of the arena to satisfy
+  a new malloc request, this much padding is added to the sbrk
+  request.
+
+  * When malloc_trim is called automatically from free(),
+  it is used as the `pad' argument.
+
+  In both cases, the actual amount of padding is rounded
+  so that the end of the arena is always a system page boundary.
+
+  The main reason for using padding is to avoid calling sbrk so
+  often. Having even a small pad greatly reduces the likelihood
+  that nearly every malloc request during program start-up (or
+  after trimming) will invoke sbrk, which needlessly wastes
+  time.
+
+  Automatic rounding-up to page-size units is normally sufficient
+  to avoid measurable overhead, so the default is 0.  However, in
+  systems where sbrk is relatively slow, it can pay to increase
+  this value, at the expense of carrying around more memory than
+  the program needs.
+*/
+
+#define M_TOP_PAD              -2
+
+#ifndef DEFAULT_TOP_PAD
+#define DEFAULT_TOP_PAD        (0)
+#endif
+
+/*
+  MMAP_THRESHOLD_MAX and _MIN are the bounds on the dynamically
+  adjusted MMAP_THRESHOLD.
+*/
+
+#ifndef DEFAULT_MMAP_THRESHOLD_MIN
+#define DEFAULT_MMAP_THRESHOLD_MIN (128 * 1024)
+#endif
+
+#ifndef DEFAULT_MMAP_THRESHOLD_MAX
+  /* For 32-bit platforms we cannot increase the maximum mmap
+     threshold much because it is also the minimum value for the
+     maximum heap size and its alignment.  Going above 512k (i.e., 1M
+     for new heaps) wastes too much address space.  */
+# if __WORDSIZE == 32
+#  define DEFAULT_MMAP_THRESHOLD_MAX (512 * 1024)
+# else
+#  define DEFAULT_MMAP_THRESHOLD_MAX (4 * 1024 * 1024 * sizeof(long))
+# endif
+#endif
+
+/*
+  M_MMAP_THRESHOLD is the request size threshold for using mmap()
+  to service a request. Requests of at least this size that cannot
+  be allocated using already-existing space will be serviced via mmap.
+  (If enough normal freed space already exists it is used instead.)
+
+  Using mmap segregates relatively large chunks of memory so that
+  they can be individually obtained and released from the host
+  system. A request serviced through mmap is never reused by any
+  other request (at least not directly; the system may just so
+  happen to remap successive requests to the same locations).
+
+  Segregating space in this way has the benefits that:
+
+   1. Mmapped space can ALWAYS be individually released back
+      to the system, which helps keep the system level memory
+      demands of a long-lived program low.
+   2. Mapped memory can never become `locked' between
+      other chunks, as can happen with normally allocated chunks, which
+      means that even trimming via malloc_trim would not release them.
+   3. On some systems with "holes" in address spaces, mmap can obtain
+      memory that sbrk cannot.
+
+  However, it has the disadvantages that:
+
+   1. The space cannot be reclaimed, consolidated, and then
+      used to service later requests, as happens with normal chunks.
+   2. It can lead to more wastage because of mmap page alignment
+      requirements
+   3. It causes malloc performance to be more dependent on host
+      system memory management support routines which may vary in
+      implementation quality and may impose arbitrary
+      limitations. Generally, servicing a request via normal
+      malloc steps is faster than going through a system's mmap.
+
+  The advantages of mmap nearly always outweigh disadvantages for
+  "large" chunks, but the value of "large" varies across systems.  The
+  default is an empirically derived value that works well in most
+  systems.
+
+
+  Update in 2006:
+  The above was written in 2001. Since then the world has changed a lot.
+  Memory got bigger. Applications got bigger. The virtual address space
+  layout in 32 bit linux changed.
+
+  In the new situation, brk() and mmap space is shared and there are no
+  artificial limits on brk size imposed by the kernel. What is more,
+  applications have started using transient allocations larger than the
+  128Kb as was imagined in 2001.
+
+  The price for mmap is also high now; each time glibc mmaps from the
+  kernel, the kernel is forced to zero out the memory it gives to the
+  application. Zeroing memory is expensive and eats a lot of cache and
+  memory bandwidth. This has nothing to do with the efficiency of the
+  virtual memory system, by doing mmap the kernel just has no choice but
+  to zero.
+
+  In 2001, the kernel had a maximum size for brk() which was about 800
+  megabytes on 32 bit x86, at that point brk() would hit the first
+  mmaped shared libaries and couldn't expand anymore. With current 2.6
+  kernels, the VA space layout is different and brk() and mmap
+  both can span the entire heap at will.
+
+  Rather than using a static threshold for the brk/mmap tradeoff,
+  we are now using a simple dynamic one. The goal is still to avoid
+  fragmentation. The old goals we kept are
+  1) try to get the long lived large allocations to use mmap()
+  2) really large allocations should always use mmap()
+  and we're adding now:
+  3) transient allocations should use brk() to avoid forcing the kernel
+     having to zero memory over and over again
+
+  The implementation works with a sliding threshold, which is by default
+  limited to go between 128Kb and 32Mb (64Mb for 64 bitmachines) and starts
+  out at 128Kb as per the 2001 default.
+
+  This allows us to satisfy requirement 1) under the assumption that long
+  lived allocations are made early in the process' lifespan, before it has
+  started doing dynamic allocations of the same size (which will
+  increase the threshold).
+
+  The upperbound on the threshold satisfies requirement 2)
+
+  The threshold goes up in value when the application frees memory that was
+  allocated with the mmap allocator. The idea is that once the application
+  starts freeing memory of a certain size, it's highly probable that this is
+  a size the application uses for transient allocations. This estimator
+  is there to satisfy the new third requirement.
+
+*/
+
+#define M_MMAP_THRESHOLD      -3
+
+#ifndef DEFAULT_MMAP_THRESHOLD
+#define DEFAULT_MMAP_THRESHOLD DEFAULT_MMAP_THRESHOLD_MIN
+#endif
+
+/*
+  M_MMAP_MAX is the maximum number of requests to simultaneously
+  service using mmap. This parameter exists because
+  some systems have a limited number of internal tables for
+  use by mmap, and using more than a few of them may degrade
+  performance.
+
+  The default is set to a value that serves only as a safeguard.
+  Setting to 0 disables use of mmap for servicing large requests.
+*/
+
+#define M_MMAP_MAX             -4
+
+#ifndef DEFAULT_MMAP_MAX
+#define DEFAULT_MMAP_MAX       (65536)
+#endif
+
+#include <malloc.h>
+
+#ifndef RETURN_ADDRESS
+#define RETURN_ADDRESS(X_) (NULL)
+#endif
+
+/* On some platforms we can compile internal, not exported functions better.
+   Let the environment provide a macro and define it to be empty if it
+   is not available.  */
+#ifndef internal_function
+# define internal_function
+#endif
+
+/* Forward declarations.  */
+struct malloc_chunk;
+typedef struct malloc_chunk* mchunkptr;
+
+/* Internal routines.  */
+
+static void*  _int_malloc(mstate, size_t);
+static void     _int_free(mstate, mchunkptr, int);
+static void*  _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
+			   INTERNAL_SIZE_T);
+static void*  _int_memalign(mstate, size_t, size_t);
+static void*  _mid_memalign(size_t, size_t, void *);
+
+static void malloc_printerr(int action, const char *str, void *ptr, mstate av);
+
+static void* internal_function mem2mem_check(void *p, size_t sz);
+static int internal_function top_check(void);
+static void internal_function munmap_chunk(mchunkptr p);
+#if HAVE_MREMAP
+static mchunkptr internal_function mremap_chunk(mchunkptr p, size_t new_size);
+#endif
+
+static void*   malloc_check(size_t sz, const void *caller);
+static void      free_check(void* mem, const void *caller);
+static void*   realloc_check(void* oldmem, size_t bytes,
+			       const void *caller);
+static void*   memalign_check(size_t alignment, size_t bytes,
+				const void *caller);
+#ifndef NO_THREADS
+static void*   malloc_atfork(size_t sz, const void *caller);
+static void      free_atfork(void* mem, const void *caller);
+#endif
+
+/* ------------------ MMAP support ------------------  */
+
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#ifndef MAP_NORESERVE
+# define MAP_NORESERVE 0
+#endif
+
+#define MMAP(addr, size, prot, flags) \
+ __mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)
+
+
+/*
+  -----------------------  Chunk representations -----------------------
+*/
+
+
+/*
+  This struct declaration is misleading (but accurate and necessary).
+  It declares a "view" into memory allowing access to necessary
+  fields at known offsets from a given base. See explanation below.
+*/
+
+struct malloc_chunk {
+
+  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
+  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */
+
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+
+  /* Only used for large blocks: pointer to next larger size.  */
+  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
+  struct malloc_chunk* bk_nextsize;
+};
+
+
+/*
+   malloc_chunk details:
+
+    (The following includes lightly edited explanations by Colin Plumb.)
+
+    Chunks of memory are maintained using a `boundary tag' method as
+    described in e.g., Knuth or Standish.  (See the paper by Paul
+    Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a
+    survey of such techniques.)  Sizes of free chunks are stored both
+    in the front of each chunk and at the end.  This makes
+    consolidating fragmented chunks into bigger chunks very fast.  The
+    size fields also hold bits representing whether chunks are free or
+    in use.
+
+    An allocated chunk looks like this:
+
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk, if allocated            | |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of chunk, in bytes                       |M|P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             User data starts here...                          .
+	    .                                                               .
+	    .             (malloc_usable_size() bytes)                      .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of chunk                                     |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+
+    Where "chunk" is the front of the chunk for the purpose of most of
+    the malloc code, but "mem" is the pointer that is returned to the
+    user.  "Nextchunk" is the beginning of the next contiguous chunk.
+
+    Chunks always begin on even word boundaries, so the mem portion
+    (which is returned to the user) is also on an even word boundary, and
+    thus at least double-word aligned.
+
+    Free chunks are stored in circular doubly-linked lists, and look like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk                            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Forward pointer to next chunk in list             |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Back pointer to previous chunk in list            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Unused space (may be 0 bytes long)                .
+	    .                                                               .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    The P (PREV_INUSE) bit, stored in the unused low-order bit of the
+    chunk size (which is always a multiple of two words), is an in-use
+    bit for the *previous* chunk.  If that bit is *clear*, then the
+    word before the current chunk size contains the previous chunk
+    size, and can be used to find the front of the previous chunk.
+    The very first chunk allocated always has this bit set,
+    preventing access to non-existent (or non-owned) memory. If
+    prev_inuse is set for any given chunk, then you CANNOT determine
+    the size of the previous chunk, and might even get a memory
+    addressing fault when trying to do so.
+
+    Note that the `foot' of the current chunk is actually represented
+    as the prev_size of the NEXT chunk. This makes it easier to
+    deal with alignments etc but can be very confusing when trying
+    to extend or adapt this code.
+
+    The two exceptions to all this are
+
+     1. The special chunk `top' doesn't bother using the
+	trailing size field since there is no next contiguous chunk
+	that would have to index off it. After initialization, `top'
+	is forced to always exist.  If it would become less than
+	MINSIZE bytes long, it is replenished.
+
+     2. Chunks allocated via mmap, which have the second-lowest-order
+	bit M (IS_MMAPPED) set in their size fields.  Because they are
+	allocated one-by-one, each must contain its own trailing size field.
+
+*/
+
+/*
+  ---------- Size and alignment checks and conversions ----------
+*/
+
+/* conversion from malloc headers to user pointers, and back */
+
+#define chunk2mem(p)   ((void*)((char*)(p) + 2*SIZE_SZ))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ))
+
+/* The smallest possible chunk */
+#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+
+#define MINSIZE  \
+  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Check if m has acceptable alignment */
+
+#define aligned_OK(m)  (((unsigned long)(m) & MALLOC_ALIGN_MASK) == 0)
+
+#define misaligned_chunk(p) \
+  ((uintptr_t)(MALLOC_ALIGNMENT == 2 * SIZE_SZ ? (p) : chunk2mem (p)) \
+   & MALLOC_ALIGN_MASK)
+
+
+/*
+   Check if a request is so large that it would wrap around zero when
+   padded and aligned. To simplify some other code, the bound is made
+   low enough so that adding MINSIZE will also not wrap around zero.
+ */
+
+#define REQUEST_OUT_OF_RANGE(req)                                 \
+  ((unsigned long) (req) >=						      \
+   (unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE))
+
+/* pad request bytes into a usable size -- internal version */
+
+#define request2size(req)                                         \
+  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
+   MINSIZE :                                                      \
+   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
+
+/*  Same, except also perform argument check */
+
+#define checked_request2size(req, sz)                             \
+  if (REQUEST_OUT_OF_RANGE (req)) {					      \
+      __set_errno (ENOMEM);						      \
+      return 0;								      \
+    }									      \
+  (sz) = request2size (req);
+
+/*
+   --------------- Physical chunk operations ---------------
+ */
+
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
+#define PREV_INUSE 0x1
+
+/* extract inuse bit of previous chunk */
+#define prev_inuse(p)       ((p)->size & PREV_INUSE)
+
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* check for mmap()'ed chunk */
+#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED)
+
+
+/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
+   from a non-main arena.  This is only set immediately before handing
+   the chunk to the user, if necessary.  */
+#define NON_MAIN_ARENA 0x4
+
+/* check for chunk from non-main arena */
+#define chunk_non_main_arena(p) ((p)->size & NON_MAIN_ARENA)
+
+
+/*
+   Bits to mask off when extracting size
+
+   Note: IS_MMAPPED is intentionally not masked off from size field in
+   macros for which mmapped chunks should never be seen. This should
+   cause helpful core dumps to occur if it is tried by accident by
+   people extending or adapting this malloc.
+ */
+#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
+
+/* Get size, ignoring use bits */
+#define chunksize(p)         ((p)->size & ~(SIZE_BITS))
+
+
+/* Ptr to next physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))
+
+/* Ptr to previous physical malloc_chunk */
+#define prev_chunk(p) ((mchunkptr) (((char *) (p)) - ((p)->prev_size)))
+
+/* Treat space at ptr + offset as a chunk */
+#define chunk_at_offset(p, s)  ((mchunkptr) (((char *) (p)) + (s)))
+
+/* extract p's inuse bit */
+#define inuse(p)							      \
+  ((((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size) & PREV_INUSE)
+
+/* set/clear chunk as being inuse without otherwise disturbing */
+#define set_inuse(p)							      \
+  ((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size |= PREV_INUSE
+
+#define clear_inuse(p)							      \
+  ((mchunkptr) (((char *) (p)) + ((p)->size & ~SIZE_BITS)))->size &= ~(PREV_INUSE)
+
+
+/* check/set/clear inuse bits in known places */
+#define inuse_bit_at_offset(p, s)					      \
+  (((mchunkptr) (((char *) (p)) + (s)))->size & PREV_INUSE)
+
+#define set_inuse_bit_at_offset(p, s)					      \
+  (((mchunkptr) (((char *) (p)) + (s)))->size |= PREV_INUSE)
+
+#define clear_inuse_bit_at_offset(p, s)					      \
+  (((mchunkptr) (((char *) (p)) + (s)))->size &= ~(PREV_INUSE))
+
+
+/* Set size at head, without disturbing its use bit */
+#define set_head_size(p, s)  ((p)->size = (((p)->size & SIZE_BITS) | (s)))
+
+/* Set size/use field */
+#define set_head(p, s)       ((p)->size = (s))
+
+/* Set size at footer (only when chunk is not in use) */
+#define set_foot(p, s)       (((mchunkptr) ((char *) (p) + (s)))->prev_size = (s))
+
+
+/*
+   -------------------- Internal data structures --------------------
+
+   All internal state is held in an instance of malloc_state defined
+   below. There are no other static variables, except in two optional
+   cases:
+ * If USE_MALLOC_LOCK is defined, the mALLOC_MUTEx declared above.
+ * If mmap doesn't support MAP_ANONYMOUS, a dummy file descriptor
+     for mmap.
+
+   Beware of lots of tricks that minimize the total bookkeeping space
+   requirements. The result is a little over 1K bytes (for 4byte
+   pointers and size_t.)
+ */
+
+/*
+   Bins
+
+    An array of bin headers for free chunks. Each bin is doubly
+    linked.  The bins are approximately proportionally (log) spaced.
+    There are a lot of these bins (128). This may look excessive, but
+    works very well in practice.  Most bins hold sizes that are
+    unusual as malloc request sizes, but are more usual for fragments
+    and consolidated sets of chunks, which is what these bins hold, so
+    they can be found quickly.  All procedures maintain the invariant
+    that no consolidated chunk physically borders another one, so each
+    chunk in a list is known to be preceeded and followed by either
+    inuse chunks or the ends of memory.
+
+    Chunks in bins are kept in size order, with ties going to the
+    approximately least recently used chunk. Ordering isn't needed
+    for the small bins, which all contain the same-sized chunks, but
+    facilitates best-fit allocation for larger chunks. These lists
+    are just sequential. Keeping them in order almost never requires
+    enough traversal to warrant using fancier ordered data
+    structures.
+
+    Chunks of the same size are linked with the most
+    recently freed at the front, and allocations are taken from the
+    back.  This results in LRU (FIFO) allocation order, which tends
+    to give each chunk an equal opportunity to be consolidated with
+    adjacent freed chunks, resulting in larger free chunks and less
+    fragmentation.
+
+    To simplify use in double-linked lists, each bin header acts
+    as a malloc_chunk. This avoids special-casing for headers.
+    But to conserve space and improve locality, we allocate
+    only the fd/bk pointers of bins, and then use repositioning tricks
+    to treat these as the fields of a malloc_chunk*.
+ */
+
+typedef struct malloc_chunk *mbinptr;
+
+/* addressing -- note that bin_at(0) does not exist */
+#define bin_at(m, i) \
+  (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2]))			      \
+             - offsetof (struct malloc_chunk, fd))
+
+/* analog of ++bin */
+#define next_bin(b)  ((mbinptr) ((char *) (b) + (sizeof (mchunkptr) << 1)))
+
+/* Reminders about list directionality within bins */
+#define first(b)     ((b)->fd)
+#define last(b)      ((b)->bk)
+
+/* Take a chunk off a bin list */
+#define unlink(AV, P, BK, FD) {                                            \
+    FD = P->fd;								      \
+    BK = P->bk;								      \
+    if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
+      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
+    else {								      \
+        FD->bk = BK;							      \
+        BK->fd = FD;							      \
+        if (!in_smallbin_range (P->size)				      \
+            && __builtin_expect (P->fd_nextsize != NULL, 0)) {		      \
+	    if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)	      \
+		|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
+	      malloc_printerr (check_action,				      \
+			       "corrupted double-linked list (not small)",    \
+			       P, AV);					      \
+            if (FD->fd_nextsize == NULL) {				      \
+                if (P->fd_nextsize == P)				      \
+                  FD->fd_nextsize = FD->bk_nextsize = FD;		      \
+                else {							      \
+                    FD->fd_nextsize = P->fd_nextsize;			      \
+                    FD->bk_nextsize = P->bk_nextsize;			      \
+                    P->fd_nextsize->bk_nextsize = FD;			      \
+                    P->bk_nextsize->fd_nextsize = FD;			      \
+                  }							      \
+              } else {							      \
+                P->fd_nextsize->bk_nextsize = P->bk_nextsize;		      \
+                P->bk_nextsize->fd_nextsize = P->fd_nextsize;		      \
+              }								      \
+          }								      \
+      }									      \
+}
+
+/*
+   Indexing
+
+    Bins for sizes < 512 bytes contain chunks of all the same size, spaced
+    8 bytes apart. Larger bins are approximately logarithmically spaced:
+
+    64 bins of size       8
+    32 bins of size      64
+    16 bins of size     512
+     8 bins of size    4096
+     4 bins of size   32768
+     2 bins of size  262144
+     1 bin  of size what's left
+
+    There is actually a little bit of slop in the numbers in bin_index
+    for the sake of speed. This makes no difference elsewhere.
+
+    The bins top out around 1MB because we expect to service large
+    requests via mmap.
+
+    Bin 0 does not exist.  Bin 1 is the unordered list; if that would be
+    a valid chunk size the small bins are bumped up one.
+ */
+
+#define NBINS             128
+#define NSMALLBINS         64
+#define SMALLBIN_WIDTH    MALLOC_ALIGNMENT
+#define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > 2 * SIZE_SZ)
+#define MIN_LARGE_SIZE    ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH)
+
+#define in_smallbin_range(sz)  \
+  ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)
+
+#define smallbin_index(sz) \
+  ((SMALLBIN_WIDTH == 16 ? (((unsigned) (sz)) >> 4) : (((unsigned) (sz)) >> 3))\
+   + SMALLBIN_CORRECTION)
+
+#define largebin_index_32(sz)                                                \
+  (((((unsigned long) (sz)) >> 6) <= 38) ?  56 + (((unsigned long) (sz)) >> 6) :\
+   ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
+   ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
+   ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
+   ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
+   126)
+
+#define largebin_index_32_big(sz)                                            \
+  (((((unsigned long) (sz)) >> 6) <= 45) ?  49 + (((unsigned long) (sz)) >> 6) :\
+   ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
+   ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
+   ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
+   ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
+   126)
+
+// XXX It remains to be seen whether it is good to keep the widths of
+// XXX the buckets the same or whether it should be scaled by a factor
+// XXX of two as well.
+#define largebin_index_64(sz)                                                \
+  (((((unsigned long) (sz)) >> 6) <= 48) ?  48 + (((unsigned long) (sz)) >> 6) :\
+   ((((unsigned long) (sz)) >> 9) <= 20) ?  91 + (((unsigned long) (sz)) >> 9) :\
+   ((((unsigned long) (sz)) >> 12) <= 10) ? 110 + (((unsigned long) (sz)) >> 12) :\
+   ((((unsigned long) (sz)) >> 15) <= 4) ? 119 + (((unsigned long) (sz)) >> 15) :\
+   ((((unsigned long) (sz)) >> 18) <= 2) ? 124 + (((unsigned long) (sz)) >> 18) :\
+   126)
+
+#define largebin_index(sz) \
+  (SIZE_SZ == 8 ? largebin_index_64 (sz)                                     \
+   : MALLOC_ALIGNMENT == 16 ? largebin_index_32_big (sz)                     \
+   : largebin_index_32 (sz))
+
+#define bin_index(sz) \
+  ((in_smallbin_range (sz)) ? smallbin_index (sz) : largebin_index (sz))
+
+
+/*
+   Unsorted chunks
+
+    All remainders from chunk splits, as well as all returned chunks,
+    are first placed in the "unsorted" bin. They are then placed
+    in regular bins after malloc gives them ONE chance to be used before
+    binning. So, basically, the unsorted_chunks list acts as a queue,
+    with chunks being placed on it in free (and malloc_consolidate),
+    and taken off (to be either used or placed in bins) in malloc.
+
+    The NON_MAIN_ARENA flag is never set for unsorted chunks, so it
+    does not have to be taken into account in size comparisons.
+ */
+
+/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
+#define unsorted_chunks(M)          (bin_at (M, 1))
+
+/*
+   Top
+
+    The top-most available chunk (i.e., the one bordering the end of
+    available memory) is treated specially. It is never included in
+    any bin, is used only if no other chunk is available, and is
+    released back to the system if it is very large (see
+    M_TRIM_THRESHOLD).  Because top initially
+    points to its own bin with initial zero size, thus forcing
+    extension on the first malloc request, we avoid having any special
+    code in malloc to check whether it even exists yet. But we still
+    need to do so when getting memory from system, so we make
+    initial_top treat the bin as a legal but unusable chunk during the
+    interval between initialization and the first call to
+    sysmalloc. (This is somewhat delicate, since it relies on
+    the 2 preceding words to be zero during this interval as well.)
+ */
+
+/* Conveniently, the unsorted bin can be used as dummy top on first call */
+#define initial_top(M)              (unsorted_chunks (M))
+
+/*
+   Binmap
+
+    To help compensate for the large number of bins, a one-level index
+    structure is used for bin-by-bin searching.  `binmap' is a
+    bitvector recording whether bins are definitely empty so they can
+    be skipped over during during traversals.  The bits are NOT always
+    cleared as soon as bins are empty, but instead only
+    when they are noticed to be empty during traversal in malloc.
+ */
+
+/* Conservatively use 32 bits per map word, even if on 64bit system */
+#define BINMAPSHIFT      5
+#define BITSPERMAP       (1U << BINMAPSHIFT)
+#define BINMAPSIZE       (NBINS / BITSPERMAP)
+
+#define idx2block(i)     ((i) >> BINMAPSHIFT)
+#define idx2bit(i)       ((1U << ((i) & ((1U << BINMAPSHIFT) - 1))))
+
+#define mark_bin(m, i)    ((m)->binmap[idx2block (i)] |= idx2bit (i))
+#define unmark_bin(m, i)  ((m)->binmap[idx2block (i)] &= ~(idx2bit (i)))
+#define get_binmap(m, i)  ((m)->binmap[idx2block (i)] & idx2bit (i))
+
+/*
+   Fastbins
+
+    An array of lists holding recently freed small chunks.  Fastbins
+    are not doubly linked.  It is faster to single-link them, and
+    since chunks are never removed from the middles of these lists,
+    double linking is not necessary. Also, unlike regular bins, they
+    are not even processed in FIFO order (they use faster LIFO) since
+    ordering doesn't much matter in the transient contexts in which
+    fastbins are normally used.
+
+    Chunks in fastbins keep their inuse bit set, so they cannot
+    be consolidated with other free chunks. malloc_consolidate
+    releases all chunks in fastbins and consolidates them with
+    other free chunks.
+ */
+
+typedef struct malloc_chunk *mfastbinptr;
+#define fastbin(ar_ptr, idx) ((ar_ptr)->fastbinsY[idx])
+
+/* offset 2 to use otherwise unindexable first 2 bins */
+#define fastbin_index(sz) \
+  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
+
+
+/* The maximum fastbin request size we support */
+#define MAX_FAST_SIZE     (80 * SIZE_SZ / 4)
+
+#define NFASTBINS  (fastbin_index (request2size (MAX_FAST_SIZE)) + 1)
+
+/*
+   FASTBIN_CONSOLIDATION_THRESHOLD is the size of a chunk in free()
+   that triggers automatic consolidation of possibly-surrounding
+   fastbin chunks. This is a heuristic, so the exact value should not
+   matter too much. It is defined at half the default trim threshold as a
+   compromise heuristic to only attempt consolidation if it is likely
+   to lead to trimming. However, it is not dynamically tunable, since
+   consolidation reduces fragmentation surrounding large chunks even
+   if trimming is not used.
+ */
+
+#define FASTBIN_CONSOLIDATION_THRESHOLD  (65536UL)
+
+/*
+   Since the lowest 2 bits in max_fast don't matter in size comparisons,
+   they are used as flags.
+ */
+
+/*
+   FASTCHUNKS_BIT held in max_fast indicates that there are probably
+   some fastbin chunks. It is set true on entering a chunk into any
+   fastbin, and cleared only in malloc_consolidate.
+
+   The truth value is inverted so that have_fastchunks will be true
+   upon startup (since statics are zero-filled), simplifying
+   initialization checks.
+ */
+
+#define FASTCHUNKS_BIT        (1U)
+
+#define have_fastchunks(M)     (((M)->flags & FASTCHUNKS_BIT) == 0)
+#define clear_fastchunks(M)    catomic_or (&(M)->flags, FASTCHUNKS_BIT)
+#define set_fastchunks(M)      catomic_and (&(M)->flags, ~FASTCHUNKS_BIT)
+
+/*
+   NONCONTIGUOUS_BIT indicates that MORECORE does not return contiguous
+   regions.  Otherwise, contiguity is exploited in merging together,
+   when possible, results from consecutive MORECORE calls.
+
+   The initial value comes from MORECORE_CONTIGUOUS, but is
+   changed dynamically if mmap is ever used as an sbrk substitute.
+ */
+
+#define NONCONTIGUOUS_BIT     (2U)
+
+#define contiguous(M)          (((M)->flags & NONCONTIGUOUS_BIT) == 0)
+#define noncontiguous(M)       (((M)->flags & NONCONTIGUOUS_BIT) != 0)
+#define set_noncontiguous(M)   ((M)->flags |= NONCONTIGUOUS_BIT)
+#define set_contiguous(M)      ((M)->flags &= ~NONCONTIGUOUS_BIT)
+
+/* ARENA_CORRUPTION_BIT is set if a memory corruption was detected on the
+   arena.  Such an arena is no longer used to allocate chunks.  Chunks
+   allocated in that arena before detecting corruption are not freed.  */
+
+#define ARENA_CORRUPTION_BIT (4U)
+
+#define arena_is_corrupt(A)	(((A)->flags & ARENA_CORRUPTION_BIT))
+#define set_arena_corrupt(A)	((A)->flags |= ARENA_CORRUPTION_BIT)
+
+/*
+   Set value of max_fast.
+   Use impossibly small value if 0.
+   Precondition: there are no existing fastbin chunks.
+   Setting the value clears fastchunk bit but preserves noncontiguous bit.
+ */
+
+#define set_max_fast(s) \
+  global_max_fast = (((s) == 0)						      \
+                     ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
+#define get_max_fast() global_max_fast
+
+
+/*
+   ----------- Internal state representation and initialization -----------
+ */
+
+struct malloc_state
+{
+  /* Serialize access.  */
+  mutex_t mutex;
+
+  /* Flags (formerly in max_fast).  */
+  int flags;
+
+  /* Fastbins */
+  mfastbinptr fastbinsY[NFASTBINS];
+
+  /* Base of the topmost chunk -- not otherwise kept in a bin */
+  mchunkptr top;
+
+  /* The remainder from the most recent split of a small request */
+  mchunkptr last_remainder;
+
+  /* Normal bins packed as described above */
+  mchunkptr bins[NBINS * 2 - 2];
+
+  /* Bitmap of bins */
+  unsigned int binmap[BINMAPSIZE];
+
+  /* Linked list */
+  struct malloc_state *next;
+
+  /* Linked list for free arenas.  Access to this field is serialized
+     by free_list_lock in arena.c.  */
+  struct malloc_state *next_free;
+
+  /* Number of threads attached to this arena.  0 if the arena is on
+     the free list.  Access to this field is serialized by
+     free_list_lock in arena.c.  */
+  INTERNAL_SIZE_T attached_threads;
+
+  /* Memory allocated from the system in this arena.  */
+  INTERNAL_SIZE_T system_mem;
+  INTERNAL_SIZE_T max_system_mem;
+};
+
+struct malloc_par
+{
+  /* Tunable parameters */
+  unsigned long trim_threshold;
+  INTERNAL_SIZE_T top_pad;
+  INTERNAL_SIZE_T mmap_threshold;
+  INTERNAL_SIZE_T arena_test;
+  INTERNAL_SIZE_T arena_max;
+
+  /* Memory map support */
+  int n_mmaps;
+  int n_mmaps_max;
+  int max_n_mmaps;
+  /* the mmap_threshold is dynamic, until the user sets
+     it manually, at which point we need to disable any
+     dynamic behavior. */
+  int no_dyn_threshold;
+
+  /* Statistics */
+  INTERNAL_SIZE_T mmapped_mem;
+  /*INTERNAL_SIZE_T  sbrked_mem;*/
+  /*INTERNAL_SIZE_T  max_sbrked_mem;*/
+  INTERNAL_SIZE_T max_mmapped_mem;
+  INTERNAL_SIZE_T max_total_mem;  /* only kept for NO_THREADS */
+
+  /* First address handed out by MORECORE/sbrk.  */
+  char *sbrk_base;
+};
+
+/* There are several instances of this struct ("arenas") in this
+   malloc.  If you are adapting this malloc in a way that does NOT use
+   a static or mmapped malloc_state, you MUST explicitly zero-fill it
+   before using. This malloc relies on the property that malloc_state
+   is initialized to all zeroes (as is true of C statics).  */
+
+static struct malloc_state main_arena =
+{
+  .mutex = _LIBC_LOCK_INITIALIZER,
+  .next = &main_arena,
+  .attached_threads = 1
+};
+
+/* There is only one instance of the malloc parameters.  */
+
+static struct malloc_par mp_ =
+{
+  .top_pad = DEFAULT_TOP_PAD,
+  .n_mmaps_max = DEFAULT_MMAP_MAX,
+  .mmap_threshold = DEFAULT_MMAP_THRESHOLD,
+  .trim_threshold = DEFAULT_TRIM_THRESHOLD,
+#define NARENAS_FROM_NCORES(n) ((n) * (sizeof (long) == 4 ? 2 : 8))
+  .arena_test = NARENAS_FROM_NCORES (1)
+};
+
+
+/*  Non public mallopt parameters.  */
+#define M_ARENA_TEST -7
+#define M_ARENA_MAX  -8
+
+
+/* Maximum size of memory handled in fastbins.  */
+static INTERNAL_SIZE_T global_max_fast;
+
+/*
+   Initialize a malloc_state struct.
+
+   This is called only from within malloc_consolidate, which needs
+   be called in the same contexts anyway.  It is never called directly
+   outside of malloc_consolidate because some optimizing compilers try
+   to inline it at all call points, which turns out not to be an
+   optimization at all. (Inlining it in malloc_consolidate is fine though.)
+ */
+
+static void
+malloc_init_state (mstate av)
+{
+  int i;
+  mbinptr bin;
+
+  /* Establish circular links for normal bins */
+  for (i = 1; i < NBINS; ++i)
+    {
+      bin = bin_at (av, i);
+      bin->fd = bin->bk = bin;
+    }
+
+#if MORECORE_CONTIGUOUS
+  if (av != &main_arena)
+#endif
+  set_noncontiguous (av);
+  if (av == &main_arena)
+    set_max_fast (DEFAULT_MXFAST);
+  av->flags |= FASTCHUNKS_BIT;
+
+  av->top = initial_top (av);
+}
+
+/*
+   Other internal utilities operating on mstates
+ */
+
+static void *sysmalloc (INTERNAL_SIZE_T, mstate);
+static int      systrim (size_t, mstate);
+static void     malloc_consolidate (mstate);
+
+
+/* -------------- Early definitions for debugging hooks ---------------- */
+
+/* Define and initialize the hook variables.  These weak definitions must
+   appear before any use of the variables in a function (arena.c uses one).  */
+#ifndef weak_variable
+/* In GNU libc we want the hook variables to be weak definitions to
+   avoid a problem with Emacs.  */
+# define weak_variable weak_function
+#endif
+
+/* Forward declarations.  */
+static void *malloc_hook_ini (size_t sz,
+                              const void *caller) __THROW;
+static void *realloc_hook_ini (void *ptr, size_t sz,
+                               const void *caller) __THROW;
+static void *memalign_hook_ini (size_t alignment, size_t sz,
+                                const void *caller) __THROW;
+
+void weak_variable (*__malloc_initialize_hook) (void) = NULL;
+void weak_variable (*__free_hook) (void *__ptr,
+                                   const void *) = NULL;
+void *weak_variable (*__malloc_hook)
+  (size_t __size, const void *) = malloc_hook_ini;
+void *weak_variable (*__realloc_hook)
+  (void *__ptr, size_t __size, const void *)
+  = realloc_hook_ini;
+void *weak_variable (*__memalign_hook)
+  (size_t __alignment, size_t __size, const void *)
+  = memalign_hook_ini;
+void weak_variable (*__after_morecore_hook) (void) = NULL;
+
+
+/* ---------------- Error behavior ------------------------------------ */
+
+#ifndef DEFAULT_CHECK_ACTION
+# define DEFAULT_CHECK_ACTION 3
+#endif
+
+static int check_action = DEFAULT_CHECK_ACTION;
+
+
+/* ------------------ Testing support ----------------------------------*/
+
+static int perturb_byte;
+
+static void
+alloc_perturb (char *p, size_t n)
+{
+  if (__glibc_unlikely (perturb_byte))
+    memset (p, perturb_byte ^ 0xff, n);
+}
+
+static void
+free_perturb (char *p, size_t n)
+{
+  if (__glibc_unlikely (perturb_byte))
+    memset (p, perturb_byte, n);
+}
+
+
+
+#include <stap-probe.h>
+
+/* ------------------- Support for multiple arenas -------------------- */
+#include "arena.c"
+
+/*
+   Debugging support
+
+   These routines make a number of assertions about the states
+   of data structures that should be true at all times. If any
+   are not true, it's very likely that a user program has somehow
+   trashed memory. (It's also possible that there is a coding error
+   in malloc. In which case, please report it!)
+ */
+
+#if !MALLOC_DEBUG
+
+# define check_chunk(A, P)
+# define check_free_chunk(A, P)
+# define check_inuse_chunk(A, P)
+# define check_remalloced_chunk(A, P, N)
+# define check_malloced_chunk(A, P, N)
+# define check_malloc_state(A)
+
+#else
+
+# define check_chunk(A, P)              do_check_chunk (A, P)
+# define check_free_chunk(A, P)         do_check_free_chunk (A, P)
+# define check_inuse_chunk(A, P)        do_check_inuse_chunk (A, P)
+# define check_remalloced_chunk(A, P, N) do_check_remalloced_chunk (A, P, N)
+# define check_malloced_chunk(A, P, N)   do_check_malloced_chunk (A, P, N)
+# define check_malloc_state(A)         do_check_malloc_state (A)
+
+/*
+   Properties of all chunks
+ */
+
+static void
+do_check_chunk (mstate av, mchunkptr p)
+{
+  unsigned long sz = chunksize (p);
+  /* min and max possible addresses assuming contiguous allocation */
+  char *max_address = (char *) (av->top) + chunksize (av->top);
+  char *min_address = max_address - av->system_mem;
+
+  if (!chunk_is_mmapped (p))
+    {
+      /* Has legal address ... */
+      if (p != av->top)
+        {
+          if (contiguous (av))
+            {
+              assert (((char *) p) >= min_address);
+              assert (((char *) p + sz) <= ((char *) (av->top)));
+            }
+        }
+      else
+        {
+          /* top size is always at least MINSIZE */
+          assert ((unsigned long) (sz) >= MINSIZE);
+          /* top predecessor always marked inuse */
+          assert (prev_inuse (p));
+        }
+    }
+  else
+    {
+      /* address is outside main heap  */
+      if (contiguous (av) && av->top != initial_top (av))
+        {
+          assert (((char *) p) < min_address || ((char *) p) >= max_address);
+        }
+      /* chunk is page-aligned */
+      assert (((p->prev_size + sz) & (GLRO (dl_pagesize) - 1)) == 0);
+      /* mem is aligned */
+      assert (aligned_OK (chunk2mem (p)));
+    }
+}
+
+/*
+   Properties of free chunks
+ */
+
+static void
+do_check_free_chunk (mstate av, mchunkptr p)
+{
+  INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE | NON_MAIN_ARENA);
+  mchunkptr next = chunk_at_offset (p, sz);
+
+  do_check_chunk (av, p);
+
+  /* Chunk must claim to be free ... */
+  assert (!inuse (p));
+  assert (!chunk_is_mmapped (p));
+
+  /* Unless a special marker, must have OK fields */
+  if ((unsigned long) (sz) >= MINSIZE)
+    {
+      assert ((sz & MALLOC_ALIGN_MASK) == 0);
+      assert (aligned_OK (chunk2mem (p)));
+      /* ... matching footer field */
+      assert (next->prev_size == sz);
+      /* ... and is fully consolidated */
+      assert (prev_inuse (p));
+      assert (next == av->top || inuse (next));
+
+      /* ... and has minimally sane links */
+      assert (p->fd->bk == p);
+      assert (p->bk->fd == p);
+    }
+  else /* markers are always of size SIZE_SZ */
+    assert (sz == SIZE_SZ);
+}
+
+/*
+   Properties of inuse chunks
+ */
+
+static void
+do_check_inuse_chunk (mstate av, mchunkptr p)
+{
+  mchunkptr next;
+
+  do_check_chunk (av, p);
+
+  if (chunk_is_mmapped (p))
+    return; /* mmapped chunks have no next/prev */
+
+  /* Check whether it claims to be in use ... */
+  assert (inuse (p));
+
+  next = next_chunk (p);
+
+  /* ... and is surrounded by OK chunks.
+     Since more things can be checked with free chunks than inuse ones,
+     if an inuse chunk borders them and debug is on, it's worth doing them.
+   */
+  if (!prev_inuse (p))
+    {
+      /* Note that we cannot even look at prev unless it is not inuse */
+      mchunkptr prv = prev_chunk (p);
+      assert (next_chunk (prv) == p);
+      do_check_free_chunk (av, prv);
+    }
+
+  if (next == av->top)
+    {
+      assert (prev_inuse (next));
+      assert (chunksize (next) >= MINSIZE);
+    }
+  else if (!inuse (next))
+    do_check_free_chunk (av, next);
+}
+
+/*
+   Properties of chunks recycled from fastbins
+ */
+
+static void
+do_check_remalloced_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T s)
+{
+  INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE | NON_MAIN_ARENA);
+
+  if (!chunk_is_mmapped (p))
+    {
+      assert (av == arena_for_chunk (p));
+      if (chunk_non_main_arena (p))
+        assert (av != &main_arena);
+      else
+        assert (av == &main_arena);
+    }
+
+  do_check_inuse_chunk (av, p);
+
+  /* Legal size ... */
+  assert ((sz & MALLOC_ALIGN_MASK) == 0);
+  assert ((unsigned long) (sz) >= MINSIZE);
+  /* ... and alignment */
+  assert (aligned_OK (chunk2mem (p)));
+  /* chunk is less than MINSIZE more than request */
+  assert ((long) (sz) - (long) (s) >= 0);
+  assert ((long) (sz) - (long) (s + MINSIZE) < 0);
+}
+
+/*
+   Properties of nonrecycled chunks at the point they are malloced
+ */
+
+static void
+do_check_malloced_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T s)
+{
+  /* same as recycled case ... */
+  do_check_remalloced_chunk (av, p, s);
+
+  /*
+     ... plus,  must obey implementation invariant that prev_inuse is
+     always true of any allocated chunk; i.e., that each allocated
+     chunk borders either a previously allocated and still in-use
+     chunk, or the base of its memory arena. This is ensured
+     by making all allocations from the `lowest' part of any found
+     chunk.  This does not necessarily hold however for chunks
+     recycled via fastbins.
+   */
+
+  assert (prev_inuse (p));
+}
+
+
+/*
+   Properties of malloc_state.
+
+   This may be useful for debugging malloc, as well as detecting user
+   programmer errors that somehow write into malloc_state.
+
+   If you are extending or experimenting with this malloc, you can
+   probably figure out how to hack this routine to print out or
+   display chunk addresses, sizes, bins, and other instrumentation.
+ */
+
+static void
+do_check_malloc_state (mstate av)
+{
+  int i;
+  mchunkptr p;
+  mchunkptr q;
+  mbinptr b;
+  unsigned int idx;
+  INTERNAL_SIZE_T size;
+  unsigned long total = 0;
+  int max_fast_bin;
+
+  /* internal size_t must be no wider than pointer type */
+  assert (sizeof (INTERNAL_SIZE_T) <= sizeof (char *));
+
+  /* alignment is a power of 2 */
+  assert ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT - 1)) == 0);
+
+  /* cannot run remaining checks until fully initialized */
+  if (av->top == 0 || av->top == initial_top (av))
+    return;
+
+  /* pagesize is a power of 2 */
+  assert (powerof2(GLRO (dl_pagesize)));
+
+  /* A contiguous main_arena is consistent with sbrk_base.  */
+  if (av == &main_arena && contiguous (av))
+    assert ((char *) mp_.sbrk_base + av->system_mem ==
+            (char *) av->top + chunksize (av->top));
+
+  /* properties of fastbins */
+
+  /* max_fast is in allowed range */
+  assert ((get_max_fast () & ~1) <= request2size (MAX_FAST_SIZE));
+
+  max_fast_bin = fastbin_index (get_max_fast ());
+
+  for (i = 0; i < NFASTBINS; ++i)
+    {
+      p = fastbin (av, i);
+
+      /* The following test can only be performed for the main arena.
+         While mallopt calls malloc_consolidate to get rid of all fast
+         bins (especially those larger than the new maximum) this does
+         only happen for the main arena.  Trying to do this for any
+         other arena would mean those arenas have to be locked and
+         malloc_consolidate be called for them.  This is excessive.  And
+         even if this is acceptable to somebody it still cannot solve
+         the problem completely since if the arena is locked a
+         concurrent malloc call might create a new arena which then
+         could use the newly invalid fast bins.  */
+
+      /* all bins past max_fast are empty */
+      if (av == &main_arena && i > max_fast_bin)
+        assert (p == 0);
+
+      while (p != 0)
+        {
+          /* each chunk claims to be inuse */
+          do_check_inuse_chunk (av, p);
+          total += chunksize (p);
+          /* chunk belongs in this bin */
+          assert (fastbin_index (chunksize (p)) == i);
+          p = p->fd;
+        }
+    }
+
+  if (total != 0)
+    assert (have_fastchunks (av));
+  else if (!have_fastchunks (av))
+    assert (total == 0);
+
+  /* check normal bins */
+  for (i = 1; i < NBINS; ++i)
+    {
+      b = bin_at (av, i);
+
+      /* binmap is accurate (except for bin 1 == unsorted_chunks) */
+      if (i >= 2)
+        {
+          unsigned int binbit = get_binmap (av, i);
+          int empty = last (b) == b;
+          if (!binbit)
+            assert (empty);
+          else if (!empty)
+            assert (binbit);
+        }
+
+      for (p = last (b); p != b; p = p->bk)
+        {
+          /* each chunk claims to be free */
+          do_check_free_chunk (av, p);
+          size = chunksize (p);
+          total += size;
+          if (i >= 2)
+            {
+              /* chunk belongs in bin */
+              idx = bin_index (size);
+              assert (idx == i);
+              /* lists are sorted */
+              assert (p->bk == b ||
+                      (unsigned long) chunksize (p->bk) >= (unsigned long) chunksize (p));
+
+              if (!in_smallbin_range (size))
+                {
+                  if (p->fd_nextsize != NULL)
+                    {
+                      if (p->fd_nextsize == p)
+                        assert (p->bk_nextsize == p);
+                      else
+                        {
+                          if (p->fd_nextsize == first (b))
+                            assert (chunksize (p) < chunksize (p->fd_nextsize));
+                          else
+                            assert (chunksize (p) > chunksize (p->fd_nextsize));
+
+                          if (p == first (b))
+                            assert (chunksize (p) > chunksize (p->bk_nextsize));
+                          else
+                            assert (chunksize (p) < chunksize (p->bk_nextsize));
+                        }
+                    }
+                  else
+                    assert (p->bk_nextsize == NULL);
+                }
+            }
+          else if (!in_smallbin_range (size))
+            assert (p->fd_nextsize == NULL && p->bk_nextsize == NULL);
+          /* chunk is followed by a legal chain of inuse chunks */
+          for (q = next_chunk (p);
+               (q != av->top && inuse (q) &&
+                (unsigned long) (chunksize (q)) >= MINSIZE);
+               q = next_chunk (q))
+            do_check_inuse_chunk (av, q);
+        }
+    }
+
+  /* top chunk is OK */
+  check_chunk (av, av->top);
+}
+#endif
+
+
+/* ----------------- Support for debugging hooks -------------------- */
+#include "hooks.c"
+
+
+/* ----------- Routines dealing with system allocation -------------- */
+
+/*
+   sysmalloc handles malloc cases requiring more memory from the system.
+   On entry, it is assumed that av->top does not have enough
+   space to service request for nb bytes, thus requiring that av->top
+   be extended or replaced.
+ */
+
+static void *
+sysmalloc (INTERNAL_SIZE_T nb, mstate av)
+{
+  mchunkptr old_top;              /* incoming value of av->top */
+  INTERNAL_SIZE_T old_size;       /* its size */
+  char *old_end;                  /* its end address */
+
+  long size;                      /* arg to first MORECORE or mmap call */
+  char *brk;                      /* return value from MORECORE */
+
+  long correction;                /* arg to 2nd MORECORE call */
+  char *snd_brk;                  /* 2nd return val */
+
+  INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of new space */
+  INTERNAL_SIZE_T end_misalign;   /* partial page left at end of new space */
+  char *aligned_brk;              /* aligned offset into brk */
+
+  mchunkptr p;                    /* the allocated/returned chunk */
+  mchunkptr remainder;            /* remainder from allocation */
+  unsigned long remainder_size;   /* its size */
+
+
+  size_t pagesize = GLRO (dl_pagesize);
+  bool tried_mmap = false;
+
+
+  /*
+     If have mmap, and the request size meets the mmap threshold, and
+     the system supports mmap, and there are few enough currently
+     allocated mmapped regions, try to directly map this request
+     rather than expanding top.
+   */
+
+  if (av == NULL
+      || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
+	  && (mp_.n_mmaps < mp_.n_mmaps_max)))
+    {
+      char *mm;           /* return value from mmap call*/
+
+    try_mmap:
+      /*
+         Round up size to nearest page.  For mmapped chunks, the overhead
+         is one SIZE_SZ unit larger than for normal chunks, because there
+         is no following chunk whose prev_size field could be used.
+
+         See the front_misalign handling below, for glibc there is no
+         need for further alignments unless we have have high alignment.
+       */
+      if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
+        size = ALIGN_UP (nb + SIZE_SZ, pagesize);
+      else
+        size = ALIGN_UP (nb + SIZE_SZ + MALLOC_ALIGN_MASK, pagesize);
+      tried_mmap = true;
+
+      /* Don't try if size wraps around 0 */
+      if ((unsigned long) (size) > (unsigned long) (nb))
+        {
+          mm = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0));
+
+          if (mm != MAP_FAILED)
+            {
+              /*
+                 The offset to the start of the mmapped region is stored
+                 in the prev_size field of the chunk. This allows us to adjust
+                 returned start address to meet alignment requirements here
+                 and in memalign(), and still be able to compute proper
+                 address argument for later munmap in free() and realloc().
+               */
+
+              if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
+                {
+                  /* For glibc, chunk2mem increases the address by 2*SIZE_SZ and
+                     MALLOC_ALIGN_MASK is 2*SIZE_SZ-1.  Each mmap'ed area is page
+                     aligned and therefore definitely MALLOC_ALIGN_MASK-aligned.  */
+                  assert (((INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK) == 0);
+                  front_misalign = 0;
+                }
+              else
+                front_misalign = (INTERNAL_SIZE_T) chunk2mem (mm) & MALLOC_ALIGN_MASK;
+              if (front_misalign > 0)
+                {
+                  correction = MALLOC_ALIGNMENT - front_misalign;
+                  p = (mchunkptr) (mm + correction);
+                  p->prev_size = correction;
+                  set_head (p, (size - correction) | IS_MMAPPED);
+                }
+              else
+                {
+                  p = (mchunkptr) mm;
+                  set_head (p, size | IS_MMAPPED);
+                }
+
+              /* update statistics */
+
+              int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1;
+              atomic_max (&mp_.max_n_mmaps, new);
+
+              unsigned long sum;
+              sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size;
+              atomic_max (&mp_.max_mmapped_mem, sum);
+
+              check_chunk (av, p);
+
+              return chunk2mem (p);
+            }
+        }
+    }
+
+  /* There are no usable arenas and mmap also failed.  */
+  if (av == NULL)
+    return 0;
+
+  /* Record incoming configuration of top */
+
+  old_top = av->top;
+  old_size = chunksize (old_top);
+  old_end = (char *) (chunk_at_offset (old_top, old_size));
+
+  brk = snd_brk = (char *) (MORECORE_FAILURE);
+
+  /*
+     If not the first time through, we require old_size to be
+     at least MINSIZE and to have prev_inuse set.
+   */
+
+  assert ((old_top == initial_top (av) && old_size == 0) ||
+          ((unsigned long) (old_size) >= MINSIZE &&
+           prev_inuse (old_top) &&
+           ((unsigned long) old_end & (pagesize - 1)) == 0));
+
+  /* Precondition: not enough current space to satisfy nb request */
+  assert ((unsigned long) (old_size) < (unsigned long) (nb + MINSIZE));
+
+
+  if (av != &main_arena)
+    {
+      heap_info *old_heap, *heap;
+      size_t old_heap_size;
+
+      /* First try to extend the current heap. */
+      old_heap = heap_for_ptr (old_top);
+      old_heap_size = old_heap->size;
+      if ((long) (MINSIZE + nb - old_size) > 0
+          && grow_heap (old_heap, MINSIZE + nb - old_size) == 0)
+        {
+          av->system_mem += old_heap->size - old_heap_size;
+          arena_mem += old_heap->size - old_heap_size;
+          set_head (old_top, (((char *) old_heap + old_heap->size) - (char *) old_top)
+                    | PREV_INUSE);
+        }
+      else if ((heap = new_heap (nb + (MINSIZE + sizeof (*heap)), mp_.top_pad)))
+        {
+          /* Use a newly allocated heap.  */
+          heap->ar_ptr = av;
+          heap->prev = old_heap;
+          av->system_mem += heap->size;
+          arena_mem += heap->size;
+          /* Set up the new top.  */
+          top (av) = chunk_at_offset (heap, sizeof (*heap));
+          set_head (top (av), (heap->size - sizeof (*heap)) | PREV_INUSE);
+
+          /* Setup fencepost and free the old top chunk with a multiple of
+             MALLOC_ALIGNMENT in size. */
+          /* The fencepost takes at least MINSIZE bytes, because it might
+             become the top chunk again later.  Note that a footer is set
+             up, too, although the chunk is marked in use. */
+          old_size = (old_size - MINSIZE) & ~MALLOC_ALIGN_MASK;
+          set_head (chunk_at_offset (old_top, old_size + 2 * SIZE_SZ), 0 | PREV_INUSE);
+          if (old_size >= MINSIZE)
+            {
+              set_head (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ) | PREV_INUSE);
+              set_foot (chunk_at_offset (old_top, old_size), (2 * SIZE_SZ));
+              set_head (old_top, old_size | PREV_INUSE | NON_MAIN_ARENA);
+              _int_free (av, old_top, 1);
+            }
+          else
+            {
+              set_head (old_top, (old_size + 2 * SIZE_SZ) | PREV_INUSE);
+              set_foot (old_top, (old_size + 2 * SIZE_SZ));
+            }
+        }
+      else if (!tried_mmap)
+        /* We can at least try to use to mmap memory.  */
+        goto try_mmap;
+    }
+  else     /* av == main_arena */
+
+
+    { /* Request enough space for nb + pad + overhead */
+      size = nb + mp_.top_pad + MINSIZE;
+
+      /*
+         If contiguous, we can subtract out existing space that we hope to
+         combine with new space. We add it back later only if
+         we don't actually get contiguous space.
+       */
+
+      if (contiguous (av))
+        size -= old_size;
+
+      /*
+         Round to a multiple of page size.
+         If MORECORE is not contiguous, this ensures that we only call it
+         with whole-page arguments.  And if MORECORE is contiguous and
+         this is not first time through, this preserves page-alignment of
+         previous calls. Otherwise, we correct to page-align below.
+       */
+
+      size = ALIGN_UP (size, pagesize);
+
+      /*
+         Don't try to call MORECORE if argument is so big as to appear
+         negative. Note that since mmap takes size_t arg, it may succeed
+         below even if we cannot call MORECORE.
+       */
+
+      if (size > 0)
+        {
+          brk = (char *) (MORECORE (size));
+          LIBC_PROBE (memory_sbrk_more, 2, brk, size);
+        }
+
+      if (brk != (char *) (MORECORE_FAILURE))
+        {
+          /* Call the `morecore' hook if necessary.  */
+          void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
+          if (__builtin_expect (hook != NULL, 0))
+            (*hook)();
+        }
+      else
+        {
+          /*
+             If have mmap, try using it as a backup when MORECORE fails or
+             cannot be used. This is worth doing on systems that have "holes" in
+             address space, so sbrk cannot extend to give contiguous space, but
+             space is available elsewhere.  Note that we ignore mmap max count
+             and threshold limits, since the space will not be used as a
+             segregated mmap region.
+           */
+
+          /* Cannot merge with old top, so add its size back in */
+          if (contiguous (av))
+            size = ALIGN_UP (size + old_size, pagesize);
+
+          /* If we are relying on mmap as backup, then use larger units */
+          if ((unsigned long) (size) < (unsigned long) (MMAP_AS_MORECORE_SIZE))
+            size = MMAP_AS_MORECORE_SIZE;
+
+          /* Don't try if size wraps around 0 */
+          if ((unsigned long) (size) > (unsigned long) (nb))
+            {
+              char *mbrk = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0));
+
+              if (mbrk != MAP_FAILED)
+                {
+                  /* We do not need, and cannot use, another sbrk call to find end */
+                  brk = mbrk;
+                  snd_brk = brk + size;
+
+                  /*
+                     Record that we no longer have a contiguous sbrk region.
+                     After the first time mmap is used as backup, we do not
+                     ever rely on contiguous space since this could incorrectly
+                     bridge regions.
+                   */
+                  set_noncontiguous (av);
+                }
+            }
+        }
+
+      if (brk != (char *) (MORECORE_FAILURE))
+        {
+          if (mp_.sbrk_base == 0)
+            mp_.sbrk_base = brk;
+          av->system_mem += size;
+
+          /*
+             If MORECORE extends previous space, we can likewise extend top size.
+           */
+
+          if (brk == old_end && snd_brk == (char *) (MORECORE_FAILURE))
+            set_head (old_top, (size + old_size) | PREV_INUSE);
+
+          else if (contiguous (av) && old_size && brk < old_end)
+            {
+              /* Oops!  Someone else killed our space..  Can't touch anything.  */
+              malloc_printerr (3, "break adjusted to free malloc space", brk,
+			       av);
+            }
+
+          /*
+             Otherwise, make adjustments:
+
+           * If the first time through or noncontiguous, we need to call sbrk
+              just to find out where the end of memory lies.
+
+           * We need to ensure that all returned chunks from malloc will meet
+              MALLOC_ALIGNMENT
+
+           * If there was an intervening foreign sbrk, we need to adjust sbrk
+              request size to account for fact that we will not be able to
+              combine new space with existing space in old_top.
+
+           * Almost all systems internally allocate whole pages at a time, in
+              which case we might as well use the whole last page of request.
+              So we allocate enough more memory to hit a page boundary now,
+              which in turn causes future contiguous calls to page-align.
+           */
+
+          else
+            {
+              front_misalign = 0;
+              end_misalign = 0;
+              correction = 0;
+              aligned_brk = brk;
+
+              /* handle contiguous cases */
+              if (contiguous (av))
+                {
+                  /* Count foreign sbrk as system_mem.  */
+                  if (old_size)
+                    av->system_mem += brk - old_end;
+
+                  /* Guarantee alignment of first new chunk made from this space */
+
+                  front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK;
+                  if (front_misalign > 0)
+                    {
+                      /*
+                         Skip over some bytes to arrive at an aligned position.
+                         We don't need to specially mark these wasted front bytes.
+                         They will never be accessed anyway because
+                         prev_inuse of av->top (and any chunk created from its start)
+                         is always true after initialization.
+                       */
+
+                      correction = MALLOC_ALIGNMENT - front_misalign;
+                      aligned_brk += correction;
+                    }
+
+                  /*
+                     If this isn't adjacent to existing space, then we will not
+                     be able to merge with old_top space, so must add to 2nd request.
+                   */
+
+                  correction += old_size;
+
+                  /* Extend the end address to hit a page boundary */
+                  end_misalign = (INTERNAL_SIZE_T) (brk + size + correction);
+                  correction += (ALIGN_UP (end_misalign, pagesize)) - end_misalign;
+
+                  assert (correction >= 0);
+                  snd_brk = (char *) (MORECORE (correction));
+
+                  /*
+                     If can't allocate correction, try to at least find out current
+                     brk.  It might be enough to proceed without failing.
+
+                     Note that if second sbrk did NOT fail, we assume that space
+                     is contiguous with first sbrk. This is a safe assumption unless
+                     program is multithreaded but doesn't use locks and a foreign sbrk
+                     occurred between our first and second calls.
+                   */
+
+                  if (snd_brk == (char *) (MORECORE_FAILURE))
+                    {
+                      correction = 0;
+                      snd_brk = (char *) (MORECORE (0));
+                    }
+                  else
+                    {
+                      /* Call the `morecore' hook if necessary.  */
+                      void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
+                      if (__builtin_expect (hook != NULL, 0))
+                        (*hook)();
+                    }
+                }
+
+              /* handle non-contiguous cases */
+              else
+                {
+                  if (MALLOC_ALIGNMENT == 2 * SIZE_SZ)
+                    /* MORECORE/mmap must correctly align */
+                    assert (((unsigned long) chunk2mem (brk) & MALLOC_ALIGN_MASK) == 0);
+                  else
+                    {
+                      front_misalign = (INTERNAL_SIZE_T) chunk2mem (brk) & MALLOC_ALIGN_MASK;
+                      if (front_misalign > 0)
+                        {
+                          /*
+                             Skip over some bytes to arrive at an aligned position.
+                             We don't need to specially mark these wasted front bytes.
+                             They will never be accessed anyway because
+                             prev_inuse of av->top (and any chunk created from its start)
+                             is always true after initialization.
+                           */
+
+                          aligned_brk += MALLOC_ALIGNMENT - front_misalign;
+                        }
+                    }
+
+                  /* Find out current end of memory */
+                  if (snd_brk == (char *) (MORECORE_FAILURE))
+                    {
+                      snd_brk = (char *) (MORECORE (0));
+                    }
+                }
+
+              /* Adjust top based on results of second sbrk */
+              if (snd_brk != (char *) (MORECORE_FAILURE))
+                {
+                  av->top = (mchunkptr) aligned_brk;
+                  set_head (av->top, (snd_brk - aligned_brk + correction) | PREV_INUSE);
+                  av->system_mem += correction;
+
+                  /*
+                     If not the first time through, we either have a
+                     gap due to foreign sbrk or a non-contiguous region.  Insert a
+                     double fencepost at old_top to prevent consolidation with space
+                     we don't own. These fenceposts are artificial chunks that are
+                     marked as inuse and are in any case too small to use.  We need
+                     two to make sizes and alignments work out.
+                   */
+
+                  if (old_size != 0)
+                    {
+                      /*
+                         Shrink old_top to insert fenceposts, keeping size a
+                         multiple of MALLOC_ALIGNMENT. We know there is at least
+                         enough space in old_top to do this.
+                       */
+                      old_size = (old_size - 4 * SIZE_SZ) & ~MALLOC_ALIGN_MASK;
+                      set_head (old_top, old_size | PREV_INUSE);
+
+                      /*
+                         Note that the following assignments completely overwrite
+                         old_top when old_size was previously MINSIZE.  This is
+                         intentional. We need the fencepost, even if old_top otherwise gets
+                         lost.
+                       */
+                      chunk_at_offset (old_top, old_size)->size =
+                        (2 * SIZE_SZ) | PREV_INUSE;
+
+                      chunk_at_offset (old_top, old_size + 2 * SIZE_SZ)->size =
+                        (2 * SIZE_SZ) | PREV_INUSE;
+
+                      /* If possible, release the rest. */
+                      if (old_size >= MINSIZE)
+                        {
+                          _int_free (av, old_top, 1);
+                        }
+                    }
+                }
+            }
+        }
+    } /* if (av !=  &main_arena) */
+
+  if ((unsigned long) av->system_mem > (unsigned long) (av->max_system_mem))
+    av->max_system_mem = av->system_mem;
+  check_malloc_state (av);
+
+  /* finally, do the allocation */
+  p = av->top;
+  size = chunksize (p);
+
+  /* check that one of the above allocation paths succeeded */
+  if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
+    {
+      remainder_size = size - nb;
+      remainder = chunk_at_offset (p, nb);
+      av->top = remainder;
+      set_head (p, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0));
+      set_head (remainder, remainder_size | PREV_INUSE);
+      check_malloced_chunk (av, p, nb);
+      return chunk2mem (p);
+    }
+
+  /* catch all failure paths */
+  __set_errno (ENOMEM);
+  return 0;
+}
+
+
+/*
+   systrim is an inverse of sorts to sysmalloc.  It gives memory back
+   to the system (via negative arguments to sbrk) if there is unused
+   memory at the `high' end of the malloc pool. It is called
+   automatically by free() when top space exceeds the trim
+   threshold. It is also called by the public malloc_trim routine.  It
+   returns 1 if it actually released any memory, else 0.
+ */
+
+static int
+systrim (size_t pad, mstate av)
+{
+  long top_size;         /* Amount of top-most memory */
+  long extra;            /* Amount to release */
+  long released;         /* Amount actually released */
+  char *current_brk;     /* address returned by pre-check sbrk call */
+  char *new_brk;         /* address returned by post-check sbrk call */
+  size_t pagesize;
+  long top_area;
+
+  pagesize = GLRO (dl_pagesize);
+  top_size = chunksize (av->top);
+
+  top_area = top_size - MINSIZE - 1;
+  if (top_area <= pad)
+    return 0;
+
+  /* Release in pagesize units and round down to the nearest page.  */
+  extra = ALIGN_DOWN(top_area - pad, pagesize);
+
+  if (extra == 0)
+    return 0;
+
+  /*
+     Only proceed if end of memory is where we last set it.
+     This avoids problems if there were foreign sbrk calls.
+   */
+  current_brk = (char *) (MORECORE (0));
+  if (current_brk == (char *) (av->top) + top_size)
+    {
+      /*
+         Attempt to release memory. We ignore MORECORE return value,
+         and instead call again to find out where new end of memory is.
+         This avoids problems if first call releases less than we asked,
+         of if failure somehow altered brk value. (We could still
+         encounter problems if it altered brk in some very bad way,
+         but the only thing we can do is adjust anyway, which will cause
+         some downstream failure.)
+       */
+
+      MORECORE (-extra);
+      /* Call the `morecore' hook if necessary.  */
+      void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
+      if (__builtin_expect (hook != NULL, 0))
+        (*hook)();
+      new_brk = (char *) (MORECORE (0));
+
+      LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra);
+
+      if (new_brk != (char *) MORECORE_FAILURE)
+        {
+          released = (long) (current_brk - new_brk);
+
+          if (released != 0)
+            {
+              /* Success. Adjust top. */
+              av->system_mem -= released;
+              set_head (av->top, (top_size - released) | PREV_INUSE);
+              check_malloc_state (av);
+              return 1;
+            }
+        }
+    }
+  return 0;
+}
+
+static void
+internal_function
+munmap_chunk (mchunkptr p)
+{
+  INTERNAL_SIZE_T size = chunksize (p);
+
+  assert (chunk_is_mmapped (p));
+
+  uintptr_t block = (uintptr_t) p - p->prev_size;
+  size_t total_size = p->prev_size + size;
+  /* Unfortunately we have to do the compilers job by hand here.  Normally
+     we would test BLOCK and TOTAL-SIZE separately for compliance with the
+     page size.  But gcc does not recognize the optimization possibility
+     (in the moment at least) so we combine the two values into one before
+     the bit test.  */
+  if (__builtin_expect (((block | total_size) & (GLRO (dl_pagesize) - 1)) != 0, 0))
+    {
+      malloc_printerr (check_action, "munmap_chunk(): invalid pointer",
+                       chunk2mem (p), NULL);
+      return;
+    }
+
+  atomic_decrement (&mp_.n_mmaps);
+  atomic_add (&mp_.mmapped_mem, -total_size);
+
+  /* If munmap failed the process virtual memory address space is in a
+     bad shape.  Just leave the block hanging around, the process will
+     terminate shortly anyway since not much can be done.  */
+  __munmap ((char *) block, total_size);
+}
+
+#if HAVE_MREMAP
+
+static mchunkptr
+internal_function
+mremap_chunk (mchunkptr p, size_t new_size)
+{
+  size_t pagesize = GLRO (dl_pagesize);
+  INTERNAL_SIZE_T offset = p->prev_size;
+  INTERNAL_SIZE_T size = chunksize (p);
+  char *cp;
+
+  assert (chunk_is_mmapped (p));
+  assert (((size + offset) & (GLRO (dl_pagesize) - 1)) == 0);
+
+  /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */
+  new_size = ALIGN_UP (new_size + offset + SIZE_SZ, pagesize);
+
+  /* No need to remap if the number of pages does not change.  */
+  if (size + offset == new_size)
+    return p;
+
+  cp = (char *) __mremap ((char *) p - offset, size + offset, new_size,
+                          MREMAP_MAYMOVE);
+
+  if (cp == MAP_FAILED)
+    return 0;
+
+  p = (mchunkptr) (cp + offset);
+
+  assert (aligned_OK (chunk2mem (p)));
+
+  assert ((p->prev_size == offset));
+  set_head (p, (new_size - offset) | IS_MMAPPED);
+
+  INTERNAL_SIZE_T new;
+  new = atomic_exchange_and_add (&mp_.mmapped_mem, new_size - size - offset)
+        + new_size - size - offset;
+  atomic_max (&mp_.max_mmapped_mem, new);
+  return p;
+}
+#endif /* HAVE_MREMAP */
+
+/*------------------------ Public wrappers. --------------------------------*/
+
+void *
+__libc_malloc (size_t bytes)
+{
+  mstate ar_ptr;
+  void *victim;
+
+  void *(*hook) (size_t, const void *)
+    = atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(bytes, RETURN_ADDRESS (0));
+
+  arena_get (ar_ptr, bytes);
+
+  victim = _int_malloc (ar_ptr, bytes);
+  /* Retry with another arena only if we were able to find a usable arena
+     before.  */
+  if (!victim && ar_ptr != NULL)
+    {
+      LIBC_PROBE (memory_malloc_retry, 1, bytes);
+      ar_ptr = arena_get_retry (ar_ptr, bytes);
+      victim = _int_malloc (ar_ptr, bytes);
+    }
+
+  if (ar_ptr != NULL)
+    (void) mutex_unlock (&ar_ptr->mutex);
+
+  assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
+          ar_ptr == arena_for_chunk (mem2chunk (victim)));
+  return victim;
+}
+libc_hidden_def (__libc_malloc)
+
+void
+__libc_free (void *mem)
+{
+  mstate ar_ptr;
+  mchunkptr p;                          /* chunk corresponding to mem */
+
+  void (*hook) (void *, const void *)
+    = atomic_forced_read (__free_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      (*hook)(mem, RETURN_ADDRESS (0));
+      return;
+    }
+
+  if (mem == 0)                              /* free(0) has no effect */
+    return;
+
+  p = mem2chunk (mem);
+
+  if (chunk_is_mmapped (p))                       /* release mmapped memory. */
+    {
+      /* see if the dynamic brk/mmap threshold needs adjusting */
+      if (!mp_.no_dyn_threshold
+          && p->size > mp_.mmap_threshold
+          && p->size <= DEFAULT_MMAP_THRESHOLD_MAX)
+        {
+          mp_.mmap_threshold = chunksize (p);
+          mp_.trim_threshold = 2 * mp_.mmap_threshold;
+          LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
+                      mp_.mmap_threshold, mp_.trim_threshold);
+        }
+      munmap_chunk (p);
+      return;
+    }
+
+  ar_ptr = arena_for_chunk (p);
+  _int_free (ar_ptr, p, 0);
+}
+libc_hidden_def (__libc_free)
+
+void *
+__libc_realloc (void *oldmem, size_t bytes)
+{
+  mstate ar_ptr;
+  INTERNAL_SIZE_T nb;         /* padded request size */
+
+  void *newp;             /* chunk to return */
+
+  void *(*hook) (void *, size_t, const void *) =
+    atomic_forced_read (__realloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
+
+#if REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0 && oldmem != NULL)
+    {
+      __libc_free (oldmem); return 0;
+    }
+#endif
+
+  /* realloc of null is supposed to be same as malloc */
+  if (oldmem == 0)
+    return __libc_malloc (bytes);
+
+  /* chunk corresponding to oldmem */
+  const mchunkptr oldp = mem2chunk (oldmem);
+  /* its size */
+  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
+
+  if (chunk_is_mmapped (oldp))
+    ar_ptr = NULL;
+  else
+    ar_ptr = arena_for_chunk (oldp);
+
+  /* Little security check which won't hurt performance: the
+     allocator never wrapps around at the end of the address space.
+     Therefore we can exclude some size values which might appear
+     here by accident or by "design" from some intruder.  */
+  if (__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
+      || __builtin_expect (misaligned_chunk (oldp), 0))
+    {
+      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
+		       ar_ptr);
+      return NULL;
+    }
+
+  checked_request2size (bytes, nb);
+
+  if (chunk_is_mmapped (oldp))
+    {
+      void *newmem;
+
+#if HAVE_MREMAP
+      newp = mremap_chunk (oldp, nb);
+      if (newp)
+        return chunk2mem (newp);
+#endif
+      /* Note the extra SIZE_SZ overhead. */
+      if (oldsize - SIZE_SZ >= nb)
+        return oldmem;                         /* do nothing */
+
+      /* Must alloc, copy, free. */
+      newmem = __libc_malloc (bytes);
+      if (newmem == 0)
+        return 0;              /* propagate failure */
+
+      memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ);
+      munmap_chunk (oldp);
+      return newmem;
+    }
+
+  (void) mutex_lock (&ar_ptr->mutex);
+
+  newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
+
+  (void) mutex_unlock (&ar_ptr->mutex);
+  assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
+          ar_ptr == arena_for_chunk (mem2chunk (newp)));
+
+  if (newp == NULL)
+    {
+      /* Try harder to allocate memory in other arenas.  */
+      LIBC_PROBE (memory_realloc_retry, 2, bytes, oldmem);
+      newp = __libc_malloc (bytes);
+      if (newp != NULL)
+        {
+          memcpy (newp, oldmem, oldsize - SIZE_SZ);
+          _int_free (ar_ptr, oldp, 0);
+        }
+    }
+
+  return newp;
+}
+libc_hidden_def (__libc_realloc)
+
+void *
+__libc_memalign (size_t alignment, size_t bytes)
+{
+  void *address = RETURN_ADDRESS (0);
+  return _mid_memalign (alignment, bytes, address);
+}
+
+static void *
+_mid_memalign (size_t alignment, size_t bytes, void *address)
+{
+  mstate ar_ptr;
+  void *p;
+
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(alignment, bytes, address);
+
+  /* If we need less alignment than we give anyway, just relay to malloc.  */
+  if (alignment <= MALLOC_ALIGNMENT)
+    return __libc_malloc (bytes);
+
+  /* Otherwise, ensure that it is at least a minimum chunk size */
+  if (alignment < MINSIZE)
+    alignment = MINSIZE;
+
+  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
+     power of 2 and will cause overflow in the check below.  */
+  if (alignment > SIZE_MAX / 2 + 1)
+    {
+      __set_errno (EINVAL);
+      return 0;
+    }
+
+  /* Check for overflow.  */
+  if (bytes > SIZE_MAX - alignment - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
+
+  /* Make sure alignment is power of 2.  */
+  if (!powerof2 (alignment))
+    {
+      size_t a = MALLOC_ALIGNMENT * 2;
+      while (a < alignment)
+        a <<= 1;
+      alignment = a;
+    }
+
+  arena_get (ar_ptr, bytes + alignment + MINSIZE);
+
+  p = _int_memalign (ar_ptr, alignment, bytes);
+  if (!p && ar_ptr != NULL)
+    {
+      LIBC_PROBE (memory_memalign_retry, 2, bytes, alignment);
+      ar_ptr = arena_get_retry (ar_ptr, bytes);
+      p = _int_memalign (ar_ptr, alignment, bytes);
+    }
+
+  if (ar_ptr != NULL)
+    (void) mutex_unlock (&ar_ptr->mutex);
+
+  assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
+          ar_ptr == arena_for_chunk (mem2chunk (p)));
+  return p;
+}
+/* For ISO C11.  */
+weak_alias (__libc_memalign, aligned_alloc)
+libc_hidden_def (__libc_memalign)
+
+void *
+__libc_valloc (size_t bytes)
+{
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  void *address = RETURN_ADDRESS (0);
+  size_t pagesize = GLRO (dl_pagesize);
+  return _mid_memalign (pagesize, bytes, address);
+}
+
+void *
+__libc_pvalloc (size_t bytes)
+{
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  void *address = RETURN_ADDRESS (0);
+  size_t pagesize = GLRO (dl_pagesize);
+  size_t rounded_bytes = ALIGN_UP (bytes, pagesize);
+
+  /* Check for overflow.  */
+  if (bytes > SIZE_MAX - 2 * pagesize - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
+  return _mid_memalign (pagesize, rounded_bytes, address);
+}
+
+void *
+__libc_calloc (size_t n, size_t elem_size)
+{
+  mstate av;
+  mchunkptr oldtop, p;
+  INTERNAL_SIZE_T bytes, sz, csz, oldtopsize;
+  void *mem;
+  unsigned long clearsize;
+  unsigned long nclears;
+  INTERNAL_SIZE_T *d;
+
+  /* size_t is unsigned so the behavior on overflow is defined.  */
+  bytes = n * elem_size;
+#define HALF_INTERNAL_SIZE_T \
+  (((INTERNAL_SIZE_T) 1) << (8 * sizeof (INTERNAL_SIZE_T) / 2))
+  if (__builtin_expect ((n | elem_size) >= HALF_INTERNAL_SIZE_T, 0))
+    {
+      if (elem_size != 0 && bytes / elem_size != n)
+        {
+          __set_errno (ENOMEM);
+          return 0;
+        }
+    }
+
+  void *(*hook) (size_t, const void *) =
+    atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      sz = bytes;
+      mem = (*hook)(sz, RETURN_ADDRESS (0));
+      if (mem == 0)
+        return 0;
+
+      return memset (mem, 0, sz);
+    }
+
+  sz = bytes;
+
+  arena_get (av, sz);
+  if (av)
+    {
+      /* Check if we hand out the top chunk, in which case there may be no
+	 need to clear. */
+#if MORECORE_CLEARS
+      oldtop = top (av);
+      oldtopsize = chunksize (top (av));
+# if MORECORE_CLEARS < 2
+      /* Only newly allocated memory is guaranteed to be cleared.  */
+      if (av == &main_arena &&
+	  oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *) oldtop)
+	oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *) oldtop);
+# endif
+      if (av != &main_arena)
+	{
+	  heap_info *heap = heap_for_ptr (oldtop);
+	  if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
+	    oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
+	}
+#endif
+    }
+  else
+    {
+      /* No usable arenas.  */
+      oldtop = 0;
+      oldtopsize = 0;
+    }
+  mem = _int_malloc (av, sz);
+
+
+  assert (!mem || chunk_is_mmapped (mem2chunk (mem)) ||
+          av == arena_for_chunk (mem2chunk (mem)));
+
+  if (mem == 0 && av != NULL)
+    {
+      LIBC_PROBE (memory_calloc_retry, 1, sz);
+      av = arena_get_retry (av, sz);
+      mem = _int_malloc (av, sz);
+    }
+
+  if (av != NULL)
+    (void) mutex_unlock (&av->mutex);
+
+  /* Allocation failed even after a retry.  */
+  if (mem == 0)
+    return 0;
+
+  p = mem2chunk (mem);
+
+  /* Two optional cases in which clearing not necessary */
+  if (chunk_is_mmapped (p))
+    {
+      if (__builtin_expect (perturb_byte, 0))
+        return memset (mem, 0, sz);
+
+      return mem;
+    }
+
+  csz = chunksize (p);
+
+#if MORECORE_CLEARS
+  if (perturb_byte == 0 && (p == oldtop && csz > oldtopsize))
+    {
+      /* clear only the bytes from non-freshly-sbrked memory */
+      csz = oldtopsize;
+    }
+#endif
+
+  /* Unroll clear of <= 36 bytes (72 if 8byte sizes).  We know that
+     contents have an odd number of INTERNAL_SIZE_T-sized words;
+     minimally 3.  */
+  d = (INTERNAL_SIZE_T *) mem;
+  clearsize = csz - SIZE_SZ;
+  nclears = clearsize / sizeof (INTERNAL_SIZE_T);
+  assert (nclears >= 3);
+
+  if (nclears > 9)
+    return memset (d, 0, clearsize);
+
+  else
+    {
+      *(d + 0) = 0;
+      *(d + 1) = 0;
+      *(d + 2) = 0;
+      if (nclears > 4)
+        {
+          *(d + 3) = 0;
+          *(d + 4) = 0;
+          if (nclears > 6)
+            {
+              *(d + 5) = 0;
+              *(d + 6) = 0;
+              if (nclears > 8)
+                {
+                  *(d + 7) = 0;
+                  *(d + 8) = 0;
+                }
+            }
+        }
+    }
+
+  return mem;
+}
+
+/*
+   ------------------------------ malloc ------------------------------
+ */
+
+static void *
+_int_malloc (mstate av, size_t bytes)
+{
+  INTERNAL_SIZE_T nb;               /* normalized request size */
+  unsigned int idx;                 /* associated bin index */
+  mbinptr bin;                      /* associated bin */
+
+  mchunkptr victim;                 /* inspected/selected chunk */
+  INTERNAL_SIZE_T size;             /* its size */
+  int victim_index;                 /* its bin index */
+
+  mchunkptr remainder;              /* remainder from a split */
+  unsigned long remainder_size;     /* its size */
+
+  unsigned int block;               /* bit map traverser */
+  unsigned int bit;                 /* bit map traverser */
+  unsigned int map;                 /* current word of binmap */
+
+  mchunkptr fwd;                    /* misc temp for linking */
+  mchunkptr bck;                    /* misc temp for linking */
+
+  const char *errstr = NULL;
+
+  /*
+     Convert request size to internal form by adding SIZE_SZ bytes
+     overhead plus possibly more to obtain necessary alignment and/or
+     to obtain a size of at least MINSIZE, the smallest allocatable
+     size. Also, checked_request2size traps (returning 0) request sizes
+     that are so large that they wrap around zero when padded and
+     aligned.
+   */
+
+  checked_request2size (bytes, nb);
+
+  /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
+     mmap.  */
+  if (__glibc_unlikely (av == NULL))
+    {
+      void *p = sysmalloc (nb, av);
+      if (p != NULL)
+	alloc_perturb (p, bytes);
+      return p;
+    }
+
+  /*
+     If the size qualifies as a fastbin, first check corresponding bin.
+     This code is safe to execute even if av is not yet initialized, so we
+     can try it without checking, which saves some time on this fast path.
+   */
+
+  if ((unsigned long) (nb) <= (unsigned long) (get_max_fast ()))
+    {
+      idx = fastbin_index (nb);
+      mfastbinptr *fb = &fastbin (av, idx);
+      mchunkptr pp = *fb;
+      do
+        {
+          victim = pp;
+          if (victim == NULL)
+            break;
+        }
+      while ((pp = catomic_compare_and_exchange_val_acq (fb, victim->fd, victim))
+             != victim);
+      if (victim != 0)
+        {
+          if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
+            {
+              errstr = "malloc(): memory corruption (fast)";
+            errout:
+              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
+              return NULL;
+            }
+          check_remalloced_chunk (av, victim, nb);
+          void *p = chunk2mem (victim);
+          alloc_perturb (p, bytes);
+          return p;
+        }
+    }
+
+  /*
+     If a small request, check regular bin.  Since these "smallbins"
+     hold one size each, no searching within bins is necessary.
+     (For a large request, we need to wait until unsorted chunks are
+     processed to find best fit. But for small ones, fits are exact
+     anyway, so we can check now, which is faster.)
+   */
+
+  if (in_smallbin_range (nb))
+    {
+      idx = smallbin_index (nb);
+      bin = bin_at (av, idx);
+
+      if ((victim = last (bin)) != bin)
+        {
+          if (victim == 0) /* initialization check */
+            malloc_consolidate (av);
+          else
+            {
+              bck = victim->bk;
+	if (__glibc_unlikely (bck->fd != victim))
+                {
+                  errstr = "malloc(): smallbin double linked list corrupted";
+                  goto errout;
+                }
+              set_inuse_bit_at_offset (victim, nb);
+              bin->bk = bck;
+              bck->fd = bin;
+
+              if (av != &main_arena)
+                victim->size |= NON_MAIN_ARENA;
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+            }
+        }
+    }
+
+  /*
+     If this is a large request, consolidate fastbins before continuing.
+     While it might look excessive to kill all fastbins before
+     even seeing if there is space available, this avoids
+     fragmentation problems normally associated with fastbins.
+     Also, in practice, programs tend to have runs of either small or
+     large requests, but less often mixtures, so consolidation is not
+     invoked all that often in most programs. And the programs that
+     it is called frequently in otherwise tend to fragment.
+   */
+
+  else
+    {
+      idx = largebin_index (nb);
+      if (have_fastchunks (av))
+        malloc_consolidate (av);
+    }
+
+  /*
+     Process recently freed or remaindered chunks, taking one only if
+     it is exact fit, or, if this a small request, the chunk is remainder from
+     the most recent non-exact fit.  Place other traversed chunks in
+     bins.  Note that this step is the only place in any routine where
+     chunks are placed in bins.
+
+     The outer loop here is needed because we might not realize until
+     near the end of malloc that we should have consolidated, so must
+     do so and retry. This happens at most once, and only when we would
+     otherwise need to expand memory to service a "small" request.
+   */
+
+  for (;; )
+    {
+      int iters = 0;
+      while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
+        {
+          bck = victim->bk;
+          if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
+              || __builtin_expect (victim->size > av->system_mem, 0))
+            malloc_printerr (check_action, "malloc(): memory corruption",
+                             chunk2mem (victim), av);
+          size = chunksize (victim);
+
+          /*
+             If a small request, try to use last remainder if it is the
+             only chunk in unsorted bin.  This helps promote locality for
+             runs of consecutive small requests. This is the only
+             exception to best-fit, and applies only when there is
+             no exact fit for a small chunk.
+           */
+
+          if (in_smallbin_range (nb) &&
+              bck == unsorted_chunks (av) &&
+              victim == av->last_remainder &&
+              (unsigned long) (size) > (unsigned long) (nb + MINSIZE))
+            {
+              /* split and reattach remainder */
+              remainder_size = size - nb;
+              remainder = chunk_at_offset (victim, nb);
+              unsorted_chunks (av)->bk = unsorted_chunks (av)->fd = remainder;
+              av->last_remainder = remainder;
+              remainder->bk = remainder->fd = unsorted_chunks (av);
+              if (!in_smallbin_range (remainder_size))
+                {
+                  remainder->fd_nextsize = NULL;
+                  remainder->bk_nextsize = NULL;
+                }
+
+              set_head (victim, nb | PREV_INUSE |
+                        (av != &main_arena ? NON_MAIN_ARENA : 0));
+              set_head (remainder, remainder_size | PREV_INUSE);
+              set_foot (remainder, remainder_size);
+
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+            }
+
+          /* remove from unsorted list */
+          unsorted_chunks (av)->bk = bck;
+          bck->fd = unsorted_chunks (av);
+
+          /* Take now instead of binning if exact fit */
+
+          if (size == nb)
+            {
+              set_inuse_bit_at_offset (victim, size);
+              if (av != &main_arena)
+                victim->size |= NON_MAIN_ARENA;
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+            }
+
+          /* place chunk in bin */
+
+          if (in_smallbin_range (size))
+            {
+              victim_index = smallbin_index (size);
+              bck = bin_at (av, victim_index);
+              fwd = bck->fd;
+            }
+          else
+            {
+              victim_index = largebin_index (size);
+              bck = bin_at (av, victim_index);
+              fwd = bck->fd;
+
+              /* maintain large bins in sorted order */
+              if (fwd != bck)
+                {
+                  /* Or with inuse bit to speed comparisons */
+                  size |= PREV_INUSE;
+                  /* if smaller than smallest, bypass loop below */
+                  assert ((bck->bk->size & NON_MAIN_ARENA) == 0);
+                  if ((unsigned long) (size) < (unsigned long) (bck->bk->size))
+                    {
+                      fwd = bck;
+                      bck = bck->bk;
+
+                      victim->fd_nextsize = fwd->fd;
+                      victim->bk_nextsize = fwd->fd->bk_nextsize;
+                      fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim;
+                    }
+                  else
+                    {
+                      assert ((fwd->size & NON_MAIN_ARENA) == 0);
+                      while ((unsigned long) size < fwd->size)
+                        {
+                          fwd = fwd->fd_nextsize;
+                          assert ((fwd->size & NON_MAIN_ARENA) == 0);
+                        }
+
+                      if ((unsigned long) size == (unsigned long) fwd->size)
+                        /* Always insert in the second position.  */
+                        fwd = fwd->fd;
+                      else
+                        {
+                          victim->fd_nextsize = fwd;
+                          victim->bk_nextsize = fwd->bk_nextsize;
+                          fwd->bk_nextsize = victim;
+                          victim->bk_nextsize->fd_nextsize = victim;
+                        }
+                      bck = fwd->bk;
+                    }
+                }
+              else
+                victim->fd_nextsize = victim->bk_nextsize = victim;
+            }
+
+          mark_bin (av, victim_index);
+          victim->bk = bck;
+          victim->fd = fwd;
+          fwd->bk = victim;
+          bck->fd = victim;
+
+#define MAX_ITERS       10000
+          if (++iters >= MAX_ITERS)
+            break;
+        }
+
+      /*
+         If a large request, scan through the chunks of current bin in
+         sorted order to find smallest that fits.  Use the skip list for this.
+       */
+
+      if (!in_smallbin_range (nb))
+        {
+          bin = bin_at (av, idx);
+
+          /* skip scan if empty or largest chunk is too small */
+          if ((victim = first (bin)) != bin &&
+              (unsigned long) (victim->size) >= (unsigned long) (nb))
+            {
+              victim = victim->bk_nextsize;
+              while (((unsigned long) (size = chunksize (victim)) <
+                      (unsigned long) (nb)))
+                victim = victim->bk_nextsize;
+
+              /* Avoid removing the first entry for a size so that the skip
+                 list does not have to be rerouted.  */
+              if (victim != last (bin) && victim->size == victim->fd->size)
+                victim = victim->fd;
+
+              remainder_size = size - nb;
+              unlink (av, victim, bck, fwd);
+
+              /* Exhaust */
+              if (remainder_size < MINSIZE)
+                {
+                  set_inuse_bit_at_offset (victim, size);
+                  if (av != &main_arena)
+                    victim->size |= NON_MAIN_ARENA;
+                }
+              /* Split */
+              else
+                {
+                  remainder = chunk_at_offset (victim, nb);
+                  /* We cannot assume the unsorted list is empty and therefore
+                     have to perform a complete insert here.  */
+                  bck = unsorted_chunks (av);
+                  fwd = bck->fd;
+	  if (__glibc_unlikely (fwd->bk != bck))
+                    {
+                      errstr = "malloc(): corrupted unsorted chunks";
+                      goto errout;
+                    }
+                  remainder->bk = bck;
+                  remainder->fd = fwd;
+                  bck->fd = remainder;
+                  fwd->bk = remainder;
+                  if (!in_smallbin_range (remainder_size))
+                    {
+                      remainder->fd_nextsize = NULL;
+                      remainder->bk_nextsize = NULL;
+                    }
+                  set_head (victim, nb | PREV_INUSE |
+                            (av != &main_arena ? NON_MAIN_ARENA : 0));
+                  set_head (remainder, remainder_size | PREV_INUSE);
+                  set_foot (remainder, remainder_size);
+                }
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+            }
+        }
+
+      /*
+         Search for a chunk by scanning bins, starting with next largest
+         bin. This search is strictly by best-fit; i.e., the smallest
+         (with ties going to approximately the least recently used) chunk
+         that fits is selected.
+
+         The bitmap avoids needing to check that most blocks are nonempty.
+         The particular case of skipping all bins during warm-up phases
+         when no chunks have been returned yet is faster than it might look.
+       */
+
+      ++idx;
+      bin = bin_at (av, idx);
+      block = idx2block (idx);
+      map = av->binmap[block];
+      bit = idx2bit (idx);
+
+      for (;; )
+        {
+          /* Skip rest of block if there are no more set bits in this block.  */
+          if (bit > map || bit == 0)
+            {
+              do
+                {
+                  if (++block >= BINMAPSIZE) /* out of bins */
+                    goto use_top;
+                }
+              while ((map = av->binmap[block]) == 0);
+
+              bin = bin_at (av, (block << BINMAPSHIFT));
+              bit = 1;
+            }
+
+          /* Advance to bin with set bit. There must be one. */
+          while ((bit & map) == 0)
+            {
+              bin = next_bin (bin);
+              bit <<= 1;
+              assert (bit != 0);
+            }
+
+          /* Inspect the bin. It is likely to be non-empty */
+          victim = last (bin);
+
+          /*  If a false alarm (empty bin), clear the bit. */
+          if (victim == bin)
+            {
+              av->binmap[block] = map &= ~bit; /* Write through */
+              bin = next_bin (bin);
+              bit <<= 1;
+            }
+
+          else
+            {
+              size = chunksize (victim);
+
+              /*  We know the first chunk in this bin is big enough to use. */
+              assert ((unsigned long) (size) >= (unsigned long) (nb));
+
+              remainder_size = size - nb;
+
+              /* unlink */
+              unlink (av, victim, bck, fwd);
+
+              /* Exhaust */
+              if (remainder_size < MINSIZE)
+                {
+                  set_inuse_bit_at_offset (victim, size);
+                  if (av != &main_arena)
+                    victim->size |= NON_MAIN_ARENA;
+                }
+
+              /* Split */
+              else
+                {
+                  remainder = chunk_at_offset (victim, nb);
+
+                  /* We cannot assume the unsorted list is empty and therefore
+                     have to perform a complete insert here.  */
+                  bck = unsorted_chunks (av);
+                  fwd = bck->fd;
+	  if (__glibc_unlikely (fwd->bk != bck))
+                    {
+                      errstr = "malloc(): corrupted unsorted chunks 2";
+                      goto errout;
+                    }
+                  remainder->bk = bck;
+                  remainder->fd = fwd;
+                  bck->fd = remainder;
+                  fwd->bk = remainder;
+
+                  /* advertise as last remainder */
+                  if (in_smallbin_range (nb))
+                    av->last_remainder = remainder;
+                  if (!in_smallbin_range (remainder_size))
+                    {
+                      remainder->fd_nextsize = NULL;
+                      remainder->bk_nextsize = NULL;
+                    }
+                  set_head (victim, nb | PREV_INUSE |
+                            (av != &main_arena ? NON_MAIN_ARENA : 0));
+                  set_head (remainder, remainder_size | PREV_INUSE);
+                  set_foot (remainder, remainder_size);
+                }
+              check_malloced_chunk (av, victim, nb);
+              void *p = chunk2mem (victim);
+              alloc_perturb (p, bytes);
+              return p;
+            }
+        }
+
+    use_top:
+      /*
+         If large enough, split off the chunk bordering the end of memory
+         (held in av->top). Note that this is in accord with the best-fit
+         search rule.  In effect, av->top is treated as larger (and thus
+         less well fitting) than any other available chunk since it can
+         be extended to be as large as necessary (up to system
+         limitations).
+
+         We require that av->top always exists (i.e., has size >=
+         MINSIZE) after initialization, so if it would otherwise be
+         exhausted by current request, it is replenished. (The main
+         reason for ensuring it exists is that we may need MINSIZE space
+         to put in fenceposts in sysmalloc.)
+       */
+
+      victim = av->top;
+      size = chunksize (victim);
+
+      if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
+        {
+          remainder_size = size - nb;
+          remainder = chunk_at_offset (victim, nb);
+          av->top = remainder;
+          set_head (victim, nb | PREV_INUSE |
+                    (av != &main_arena ? NON_MAIN_ARENA : 0));
+          set_head (remainder, remainder_size | PREV_INUSE);
+
+          check_malloced_chunk (av, victim, nb);
+          void *p = chunk2mem (victim);
+          alloc_perturb (p, bytes);
+          return p;
+        }
+
+      /* When we are using atomic ops to free fast chunks we can get
+         here for all block sizes.  */
+      else if (have_fastchunks (av))
+        {
+          malloc_consolidate (av);
+          /* restore original bin index */
+          if (in_smallbin_range (nb))
+            idx = smallbin_index (nb);
+          else
+            idx = largebin_index (nb);
+        }
+
+      /*
+         Otherwise, relay to handle system-dependent cases
+       */
+      else
+        {
+          void *p = sysmalloc (nb, av);
+          if (p != NULL)
+            alloc_perturb (p, bytes);
+          return p;
+        }
+    }
+}
+
+/*
+   ------------------------------ free ------------------------------
+ */
+
+static void
+_int_free (mstate av, mchunkptr p, int have_lock)
+{
+  INTERNAL_SIZE_T size;        /* its size */
+  mfastbinptr *fb;             /* associated fastbin */
+  mchunkptr nextchunk;         /* next contiguous chunk */
+  INTERNAL_SIZE_T nextsize;    /* its size */
+  int nextinuse;               /* true if nextchunk is used */
+  INTERNAL_SIZE_T prevsize;    /* size of previous contiguous chunk */
+  mchunkptr bck;               /* misc temp for linking */
+  mchunkptr fwd;               /* misc temp for linking */
+
+  const char *errstr = NULL;
+  int locked = 0;
+
+  size = chunksize (p);
+
+  /* Little security check which won't hurt performance: the
+     allocator never wrapps around at the end of the address space.
+     Therefore we can exclude some size values which might appear
+     here by accident or by "design" from some intruder.  */
+  if (__builtin_expect ((uintptr_t) p > (uintptr_t) -size, 0)
+      || __builtin_expect (misaligned_chunk (p), 0))
+    {
+      errstr = "free(): invalid pointer";
+    errout:
+      if (!have_lock && locked)
+        (void) mutex_unlock (&av->mutex);
+      malloc_printerr (check_action, errstr, chunk2mem (p), av);
+      return;
+    }
+  /* We know that each chunk is at least MINSIZE bytes in size or a
+     multiple of MALLOC_ALIGNMENT.  */
+  if (__glibc_unlikely (size < MINSIZE || !aligned_OK (size)))
+    {
+      errstr = "free(): invalid size";
+      goto errout;
+    }
+
+  check_inuse_chunk(av, p);
+
+  /*
+    If eligible, place chunk on a fastbin so it can be found
+    and used quickly in malloc.
+  */
+
+  if ((unsigned long)(size) <= (unsigned long)(get_max_fast ())
+
+#if TRIM_FASTBINS
+      /*
+	If TRIM_FASTBINS set, don't place chunks
+	bordering top into fastbins
+      */
+      && (chunk_at_offset(p, size) != av->top)
+#endif
+      ) {
+
+    if (__builtin_expect (chunk_at_offset (p, size)->size <= 2 * SIZE_SZ, 0)
+	|| __builtin_expect (chunksize (chunk_at_offset (p, size))
+			     >= av->system_mem, 0))
+      {
+	/* We might not have a lock at this point and concurrent modifications
+	   of system_mem might have let to a false positive.  Redo the test
+	   after getting the lock.  */
+	if (have_lock
+	    || ({ assert (locked == 0);
+		  mutex_lock(&av->mutex);
+		  locked = 1;
+		  chunk_at_offset (p, size)->size <= 2 * SIZE_SZ
+		    || chunksize (chunk_at_offset (p, size)) >= av->system_mem;
+	      }))
+	  {
+	    errstr = "free(): invalid next size (fast)";
+	    goto errout;
+	  }
+	if (! have_lock)
+	  {
+	    (void)mutex_unlock(&av->mutex);
+	    locked = 0;
+	  }
+      }
+
+    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+
+    set_fastchunks(av);
+    unsigned int idx = fastbin_index(size);
+    fb = &fastbin (av, idx);
+
+    /* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */
+    mchunkptr old = *fb, old2;
+    unsigned int old_idx = ~0u;
+    do
+      {
+	/* Check that the top of the bin is not the record we are going to add
+	   (i.e., double free).  */
+	if (__builtin_expect (old == p, 0))
+	  {
+	    errstr = "double free or corruption (fasttop)";
+	    goto errout;
+	  }
+	/* Check that size of fastbin chunk at the top is the same as
+	   size of the chunk that we are adding.  We can dereference OLD
+	   only if we have the lock, otherwise it might have already been
+	   deallocated.  See use of OLD_IDX below for the actual check.  */
+	if (have_lock && old != NULL)
+	  old_idx = fastbin_index(chunksize(old));
+	p->fd = old2 = old;
+      }
+    while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
+
+    if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0))
+      {
+	errstr = "invalid fastbin entry (free)";
+	goto errout;
+      }
+  }
+
+  /*
+    Consolidate other non-mmapped chunks as they arrive.
+  */
+
+  else if (!chunk_is_mmapped(p)) {
+    if (! have_lock) {
+      (void)mutex_lock(&av->mutex);
+      locked = 1;
+    }
+
+    nextchunk = chunk_at_offset(p, size);
+
+    /* Lightweight tests: check whether the block is already the
+       top block.  */
+    if (__glibc_unlikely (p == av->top))
+      {
+	errstr = "double free or corruption (top)";
+	goto errout;
+      }
+    /* Or whether the next chunk is beyond the boundaries of the arena.  */
+    if (__builtin_expect (contiguous (av)
+			  && (char *) nextchunk
+			  >= ((char *) av->top + chunksize(av->top)), 0))
+      {
+	errstr = "double free or corruption (out)";
+	goto errout;
+      }
+    /* Or whether the block is actually not marked used.  */
+    if (__glibc_unlikely (!prev_inuse(nextchunk)))
+      {
+	errstr = "double free or corruption (!prev)";
+	goto errout;
+      }
+
+    nextsize = chunksize(nextchunk);
+    if (__builtin_expect (nextchunk->size <= 2 * SIZE_SZ, 0)
+	|| __builtin_expect (nextsize >= av->system_mem, 0))
+      {
+	errstr = "free(): invalid next size (normal)";
+	goto errout;
+      }
+
+    free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+
+    /* consolidate backward */
+    if (!prev_inuse(p)) {
+      prevsize = p->prev_size;
+      size += prevsize;
+      p = chunk_at_offset(p, -((long) prevsize));
+      unlink(av, p, bck, fwd);
+    }
+
+    if (nextchunk != av->top) {
+      /* get and clear inuse bit */
+      nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+
+      /* consolidate forward */
+      if (!nextinuse) {
+	unlink(av, nextchunk, bck, fwd);
+	size += nextsize;
+      } else
+	clear_inuse_bit_at_offset(nextchunk, 0);
+
+      /*
+	Place the chunk in unsorted chunk list. Chunks are
+	not placed into regular bins until after they have
+	been given one chance to be used in malloc.
+      */
+
+      bck = unsorted_chunks(av);
+      fwd = bck->fd;
+      if (__glibc_unlikely (fwd->bk != bck))
+	{
+	  errstr = "free(): corrupted unsorted chunks";
+	  goto errout;
+	}
+      p->fd = fwd;
+      p->bk = bck;
+      if (!in_smallbin_range(size))
+	{
+	  p->fd_nextsize = NULL;
+	  p->bk_nextsize = NULL;
+	}
+      bck->fd = p;
+      fwd->bk = p;
+
+      set_head(p, size | PREV_INUSE);
+      set_foot(p, size);
+
+      check_free_chunk(av, p);
+    }
+
+    /*
+      If the chunk borders the current high end of memory,
+      consolidate into top
+    */
+
+    else {
+      size += nextsize;
+      set_head(p, size | PREV_INUSE);
+      av->top = p;
+      check_chunk(av, p);
+    }
+
+    /*
+      If freeing a large space, consolidate possibly-surrounding
+      chunks. Then, if the total unused topmost memory exceeds trim
+      threshold, ask malloc_trim to reduce top.
+
+      Unless max_fast is 0, we don't know if there are fastbins
+      bordering top, so we cannot tell for sure whether threshold
+      has been reached unless fastbins are consolidated.  But we
+      don't want to consolidate on each free.  As a compromise,
+      consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
+      is reached.
+    */
+
+    if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
+      if (have_fastchunks(av))
+	malloc_consolidate(av);
+
+      if (av == &main_arena) {
+#ifndef MORECORE_CANNOT_TRIM
+	if ((unsigned long)(chunksize(av->top)) >=
+	    (unsigned long)(mp_.trim_threshold))
+	  systrim(mp_.top_pad, av);
+#endif
+      } else {
+	/* Always try heap_trim(), even if the top chunk is not
+	   large, because the corresponding heap might go away.  */
+	heap_info *heap = heap_for_ptr(top(av));
+
+	assert(heap->ar_ptr == av);
+	heap_trim(heap, mp_.top_pad);
+      }
+    }
+
+    if (! have_lock) {
+      assert (locked);
+      (void)mutex_unlock(&av->mutex);
+    }
+  }
+  /*
+    If the chunk was allocated via mmap, release via munmap().
+  */
+
+  else {
+    munmap_chunk (p);
+  }
+}
+
+/*
+  ------------------------- malloc_consolidate -------------------------
+
+  malloc_consolidate is a specialized version of free() that tears
+  down chunks held in fastbins.  Free itself cannot be used for this
+  purpose since, among other things, it might place chunks back onto
+  fastbins.  So, instead, we need to use a minor variant of the same
+  code.
+
+  Also, because this routine needs to be called the first time through
+  malloc anyway, it turns out to be the perfect place to trigger
+  initialization code.
+*/
+
+static void malloc_consolidate(mstate av)
+{
+  mfastbinptr*    fb;                 /* current fastbin being consolidated */
+  mfastbinptr*    maxfb;              /* last fastbin (for loop control) */
+  mchunkptr       p;                  /* current chunk being consolidated */
+  mchunkptr       nextp;              /* next chunk to consolidate */
+  mchunkptr       unsorted_bin;       /* bin header */
+  mchunkptr       first_unsorted;     /* chunk to link to */
+
+  /* These have same use as in free() */
+  mchunkptr       nextchunk;
+  INTERNAL_SIZE_T size;
+  INTERNAL_SIZE_T nextsize;
+  INTERNAL_SIZE_T prevsize;
+  int             nextinuse;
+  mchunkptr       bck;
+  mchunkptr       fwd;
+
+  /*
+    If max_fast is 0, we know that av hasn't
+    yet been initialized, in which case do so below
+  */
+
+  if (get_max_fast () != 0) {
+    clear_fastchunks(av);
+
+    unsorted_bin = unsorted_chunks(av);
+
+    /*
+      Remove each chunk from fast bin and consolidate it, placing it
+      then in unsorted bin. Among other reasons for doing this,
+      placing in unsorted bin avoids needing to calculate actual bins
+      until malloc is sure that chunks aren't immediately going to be
+      reused anyway.
+    */
+
+    maxfb = &fastbin (av, NFASTBINS - 1);
+    fb = &fastbin (av, 0);
+    do {
+      p = atomic_exchange_acq (fb, 0);
+      if (p != 0) {
+	do {
+	  check_inuse_chunk(av, p);
+	  nextp = p->fd;
+
+	  /* Slightly streamlined version of consolidation code in free() */
+	  size = p->size & ~(PREV_INUSE|NON_MAIN_ARENA);
+	  nextchunk = chunk_at_offset(p, size);
+	  nextsize = chunksize(nextchunk);
+
+	  if (!prev_inuse(p)) {
+	    prevsize = p->prev_size;
+	    size += prevsize;
+	    p = chunk_at_offset(p, -((long) prevsize));
+	    unlink(av, p, bck, fwd);
+	  }
+
+	  if (nextchunk != av->top) {
+	    nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
+
+	    if (!nextinuse) {
+	      size += nextsize;
+	      unlink(av, nextchunk, bck, fwd);
+	    } else
+	      clear_inuse_bit_at_offset(nextchunk, 0);
+
+	    first_unsorted = unsorted_bin->fd;
+	    unsorted_bin->fd = p;
+	    first_unsorted->bk = p;
+
+	    if (!in_smallbin_range (size)) {
+	      p->fd_nextsize = NULL;
+	      p->bk_nextsize = NULL;
+	    }
+
+	    set_head(p, size | PREV_INUSE);
+	    p->bk = unsorted_bin;
+	    p->fd = first_unsorted;
+	    set_foot(p, size);
+	  }
+
+	  else {
+	    size += nextsize;
+	    set_head(p, size | PREV_INUSE);
+	    av->top = p;
+	  }
+
+	} while ( (p = nextp) != 0);
+
+      }
+    } while (fb++ != maxfb);
+  }
+  else {
+    malloc_init_state(av);
+    check_malloc_state(av);
+  }
+}
+
+/*
+  ------------------------------ realloc ------------------------------
+*/
+
+void*
+_int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
+	     INTERNAL_SIZE_T nb)
+{
+  mchunkptr        newp;            /* chunk to return */
+  INTERNAL_SIZE_T  newsize;         /* its size */
+  void*          newmem;          /* corresponding user mem */
+
+  mchunkptr        next;            /* next contiguous chunk after oldp */
+
+  mchunkptr        remainder;       /* extra space at end of newp */
+  unsigned long    remainder_size;  /* its size */
+
+  mchunkptr        bck;             /* misc temp for linking */
+  mchunkptr        fwd;             /* misc temp for linking */
+
+  unsigned long    copysize;        /* bytes to copy */
+  unsigned int     ncopies;         /* INTERNAL_SIZE_T words to copy */
+  INTERNAL_SIZE_T* s;               /* copy source */
+  INTERNAL_SIZE_T* d;               /* copy destination */
+
+  const char *errstr = NULL;
+
+  /* oldmem size */
+  if (__builtin_expect (oldp->size <= 2 * SIZE_SZ, 0)
+      || __builtin_expect (oldsize >= av->system_mem, 0))
+    {
+      errstr = "realloc(): invalid old size";
+    errout:
+      malloc_printerr (check_action, errstr, chunk2mem (oldp), av);
+      return NULL;
+    }
+
+  check_inuse_chunk (av, oldp);
+
+  /* All callers already filter out mmap'ed chunks.  */
+  assert (!chunk_is_mmapped (oldp));
+
+  next = chunk_at_offset (oldp, oldsize);
+  INTERNAL_SIZE_T nextsize = chunksize (next);
+  if (__builtin_expect (next->size <= 2 * SIZE_SZ, 0)
+      || __builtin_expect (nextsize >= av->system_mem, 0))
+    {
+      errstr = "realloc(): invalid next size";
+      goto errout;
+    }
+
+  if ((unsigned long) (oldsize) >= (unsigned long) (nb))
+    {
+      /* already big enough; split below */
+      newp = oldp;
+      newsize = oldsize;
+    }
+
+  else
+    {
+      /* Try to expand forward into top */
+      if (next == av->top &&
+          (unsigned long) (newsize = oldsize + nextsize) >=
+          (unsigned long) (nb + MINSIZE))
+        {
+          set_head_size (oldp, nb | (av != &main_arena ? NON_MAIN_ARENA : 0));
+          av->top = chunk_at_offset (oldp, nb);
+          set_head (av->top, (newsize - nb) | PREV_INUSE);
+          check_inuse_chunk (av, oldp);
+          return chunk2mem (oldp);
+        }
+
+      /* Try to expand forward into next chunk;  split off remainder below */
+      else if (next != av->top &&
+               !inuse (next) &&
+               (unsigned long) (newsize = oldsize + nextsize) >=
+               (unsigned long) (nb))
+        {
+          newp = oldp;
+          unlink (av, next, bck, fwd);
+        }
+
+      /* allocate, copy, free */
+      else
+        {
+          newmem = _int_malloc (av, nb - MALLOC_ALIGN_MASK);
+          if (newmem == 0)
+            return 0; /* propagate failure */
+
+          newp = mem2chunk (newmem);
+          newsize = chunksize (newp);
+
+          /*
+             Avoid copy if newp is next chunk after oldp.
+           */
+          if (newp == next)
+            {
+              newsize += oldsize;
+              newp = oldp;
+            }
+          else
+            {
+              /*
+                 Unroll copy of <= 36 bytes (72 if 8byte sizes)
+                 We know that contents have an odd number of
+                 INTERNAL_SIZE_T-sized words; minimally 3.
+               */
+
+              copysize = oldsize - SIZE_SZ;
+              s = (INTERNAL_SIZE_T *) (chunk2mem (oldp));
+              d = (INTERNAL_SIZE_T *) (newmem);
+              ncopies = copysize / sizeof (INTERNAL_SIZE_T);
+              assert (ncopies >= 3);
+
+              if (ncopies > 9)
+                memcpy (d, s, copysize);
+
+              else
+                {
+                  *(d + 0) = *(s + 0);
+                  *(d + 1) = *(s + 1);
+                  *(d + 2) = *(s + 2);
+                  if (ncopies > 4)
+                    {
+                      *(d + 3) = *(s + 3);
+                      *(d + 4) = *(s + 4);
+                      if (ncopies > 6)
+                        {
+                          *(d + 5) = *(s + 5);
+                          *(d + 6) = *(s + 6);
+                          if (ncopies > 8)
+                            {
+                              *(d + 7) = *(s + 7);
+                              *(d + 8) = *(s + 8);
+                            }
+                        }
+                    }
+                }
+
+              _int_free (av, oldp, 1);
+              check_inuse_chunk (av, newp);
+              return chunk2mem (newp);
+            }
+        }
+    }
+
+  /* If possible, free extra space in old or extended chunk */
+
+  assert ((unsigned long) (newsize) >= (unsigned long) (nb));
+
+  remainder_size = newsize - nb;
+
+  if (remainder_size < MINSIZE)   /* not enough extra to split off */
+    {
+      set_head_size (newp, newsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
+      set_inuse_bit_at_offset (newp, newsize);
+    }
+  else   /* split remainder */
+    {
+      remainder = chunk_at_offset (newp, nb);
+      set_head_size (newp, nb | (av != &main_arena ? NON_MAIN_ARENA : 0));
+      set_head (remainder, remainder_size | PREV_INUSE |
+                (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 (av, remainder, 1);
+    }
+
+  check_inuse_chunk (av, newp);
+  return chunk2mem (newp);
+}
+
+/*
+   ------------------------------ memalign ------------------------------
+ */
+
+static void *
+_int_memalign (mstate av, size_t alignment, size_t bytes)
+{
+  INTERNAL_SIZE_T nb;             /* padded  request size */
+  char *m;                        /* memory returned by malloc call */
+  mchunkptr p;                    /* corresponding chunk */
+  char *brk;                      /* alignment point within p */
+  mchunkptr newp;                 /* chunk to return */
+  INTERNAL_SIZE_T newsize;        /* its size */
+  INTERNAL_SIZE_T leadsize;       /* leading space before alignment point */
+  mchunkptr remainder;            /* spare room at end to split off */
+  unsigned long remainder_size;   /* its size */
+  INTERNAL_SIZE_T size;
+
+
+
+  checked_request2size (bytes, nb);
+
+  /*
+     Strategy: find a spot within that chunk that meets the alignment
+     request, and then possibly free the leading and trailing space.
+   */
+
+
+  /* Call malloc with worst case padding to hit alignment. */
+
+  m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
+
+  if (m == 0)
+    return 0;           /* propagate failure */
+
+  p = mem2chunk (m);
+
+  if ((((unsigned long) (m)) % alignment) != 0)   /* misaligned */
+
+    { /*
+                Find an aligned spot inside chunk.  Since we need to give back
+                leading space in a chunk of at least MINSIZE, if the first
+                calculation places us at a spot with less than MINSIZE leader,
+                we can move to the next aligned spot -- we've allocated enough
+                total room so that this is always possible.
+                 */
+      brk = (char *) mem2chunk (((unsigned long) (m + alignment - 1)) &
+                                - ((signed long) alignment));
+      if ((unsigned long) (brk - (char *) (p)) < MINSIZE)
+        brk += alignment;
+
+      newp = (mchunkptr) brk;
+      leadsize = brk - (char *) (p);
+      newsize = chunksize (p) - leadsize;
+
+      /* For mmapped chunks, just adjust offset */
+      if (chunk_is_mmapped (p))
+        {
+          newp->prev_size = p->prev_size + leadsize;
+          set_head (newp, newsize | IS_MMAPPED);
+          return chunk2mem (newp);
+        }
+
+      /* Otherwise, give back leader, use the rest */
+      set_head (newp, newsize | PREV_INUSE |
+                (av != &main_arena ? NON_MAIN_ARENA : 0));
+      set_inuse_bit_at_offset (newp, newsize);
+      set_head_size (p, leadsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
+      _int_free (av, p, 1);
+      p = newp;
+
+      assert (newsize >= nb &&
+              (((unsigned long) (chunk2mem (p))) % alignment) == 0);
+    }
+
+  /* Also give back spare room at the end */
+  if (!chunk_is_mmapped (p))
+    {
+      size = chunksize (p);
+      if ((unsigned long) (size) > (unsigned long) (nb + MINSIZE))
+        {
+          remainder_size = size - nb;
+          remainder = chunk_at_offset (p, nb);
+          set_head (remainder, remainder_size | PREV_INUSE |
+                    (av != &main_arena ? NON_MAIN_ARENA : 0));
+          set_head_size (p, nb);
+          _int_free (av, remainder, 1);
+        }
+    }
+
+  check_inuse_chunk (av, p);
+  return chunk2mem (p);
+}
+
+
+/*
+   ------------------------------ malloc_trim ------------------------------
+ */
+
+static int
+mtrim (mstate av, size_t pad)
+{
+  /* Don't touch corrupt arenas.  */
+  if (arena_is_corrupt (av))
+    return 0;
+
+  /* Ensure initialization/consolidation */
+  malloc_consolidate (av);
+
+  const size_t ps = GLRO (dl_pagesize);
+  int psindex = bin_index (ps);
+  const size_t psm1 = ps - 1;
+
+  int result = 0;
+  for (int i = 1; i < NBINS; ++i)
+    if (i == 1 || i >= psindex)
+      {
+        mbinptr bin = bin_at (av, i);
+
+        for (mchunkptr p = last (bin); p != bin; p = p->bk)
+          {
+            INTERNAL_SIZE_T size = chunksize (p);
+
+            if (size > psm1 + sizeof (struct malloc_chunk))
+              {
+                /* See whether the chunk contains at least one unused page.  */
+                char *paligned_mem = (char *) (((uintptr_t) p
+                                                + sizeof (struct malloc_chunk)
+                                                + psm1) & ~psm1);
+
+                assert ((char *) chunk2mem (p) + 4 * SIZE_SZ <= paligned_mem);
+                assert ((char *) p + size > paligned_mem);
+
+                /* This is the size we could potentially free.  */
+                size -= paligned_mem - (char *) p;
+
+                if (size > psm1)
+                  {
+#if MALLOC_DEBUG
+                    /* When debugging we simulate destroying the memory
+                       content.  */
+                    memset (paligned_mem, 0x89, size & ~psm1);
+#endif
+                    __madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);
+
+                    result = 1;
+                  }
+              }
+          }
+      }
+
+#ifndef MORECORE_CANNOT_TRIM
+  return result | (av == &main_arena ? systrim (pad, av) : 0);
+
+#else
+  return result;
+#endif
+}
+
+
+int
+__malloc_trim (size_t s)
+{
+  int result = 0;
+
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  mstate ar_ptr = &main_arena;
+  do
+    {
+      (void) mutex_lock (&ar_ptr->mutex);
+      result |= mtrim (ar_ptr, s);
+      (void) mutex_unlock (&ar_ptr->mutex);
+
+      ar_ptr = ar_ptr->next;
+    }
+  while (ar_ptr != &main_arena);
+
+  return result;
+}
+
+
+/*
+   ------------------------- malloc_usable_size -------------------------
+ */
+
+static size_t
+musable (void *mem)
+{
+  mchunkptr p;
+  if (mem != 0)
+    {
+      p = mem2chunk (mem);
+
+      if (__builtin_expect (using_malloc_checking == 1, 0))
+        return malloc_check_get_size (p);
+
+      if (chunk_is_mmapped (p))
+        return chunksize (p) - 2 * SIZE_SZ;
+      else if (inuse (p))
+        return chunksize (p) - SIZE_SZ;
+    }
+  return 0;
+}
+
+
+size_t
+__malloc_usable_size (void *m)
+{
+  size_t result;
+
+  result = musable (m);
+  return result;
+}
+
+/*
+   ------------------------------ mallinfo ------------------------------
+   Accumulate malloc statistics for arena AV into M.
+ */
+
+static void
+int_mallinfo (mstate av, struct mallinfo *m)
+{
+  size_t i;
+  mbinptr b;
+  mchunkptr p;
+  INTERNAL_SIZE_T avail;
+  INTERNAL_SIZE_T fastavail;
+  int nblocks;
+  int nfastblocks;
+
+  /* Ensure initialization */
+  if (av->top == 0)
+    malloc_consolidate (av);
+
+  check_malloc_state (av);
+
+  /* Account for top */
+  avail = chunksize (av->top);
+  nblocks = 1;  /* top always exists */
+
+  /* traverse fastbins */
+  nfastblocks = 0;
+  fastavail = 0;
+
+  for (i = 0; i < NFASTBINS; ++i)
+    {
+      for (p = fastbin (av, i); p != 0; p = p->fd)
+        {
+          ++nfastblocks;
+          fastavail += chunksize (p);
+        }
+    }
+
+  avail += fastavail;
+
+  /* traverse regular bins */
+  for (i = 1; i < NBINS; ++i)
+    {
+      b = bin_at (av, i);
+      for (p = last (b); p != b; p = p->bk)
+        {
+          ++nblocks;
+          avail += chunksize (p);
+        }
+    }
+
+  m->smblks += nfastblocks;
+  m->ordblks += nblocks;
+  m->fordblks += avail;
+  m->uordblks += av->system_mem - avail;
+  m->arena += av->system_mem;
+  m->fsmblks += fastavail;
+  if (av == &main_arena)
+    {
+      m->hblks = mp_.n_mmaps;
+      m->hblkhd = mp_.mmapped_mem;
+      m->usmblks = mp_.max_total_mem;
+      m->keepcost = chunksize (av->top);
+    }
+}
+
+
+struct mallinfo
+__libc_mallinfo (void)
+{
+  struct mallinfo m;
+  mstate ar_ptr;
+
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  memset (&m, 0, sizeof (m));
+  ar_ptr = &main_arena;
+  do
+    {
+      (void) mutex_lock (&ar_ptr->mutex);
+      int_mallinfo (ar_ptr, &m);
+      (void) mutex_unlock (&ar_ptr->mutex);
+
+      ar_ptr = ar_ptr->next;
+    }
+  while (ar_ptr != &main_arena);
+
+  return m;
+}
+
+/*
+   ------------------------------ malloc_stats ------------------------------
+ */
+
+void
+__malloc_stats (void)
+{
+  int i;
+  mstate ar_ptr;
+  unsigned int in_use_b = mp_.mmapped_mem, system_b = in_use_b;
+
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+  _IO_flockfile (stderr);
+  int old_flags2 = ((_IO_FILE *) stderr)->_flags2;
+  ((_IO_FILE *) stderr)->_flags2 |= _IO_FLAGS2_NOTCANCEL;
+  for (i = 0, ar_ptr = &main_arena;; i++)
+    {
+      struct mallinfo mi;
+
+      memset (&mi, 0, sizeof (mi));
+      (void) mutex_lock (&ar_ptr->mutex);
+      int_mallinfo (ar_ptr, &mi);
+      fprintf (stderr, "Arena %d:\n", i);
+      fprintf (stderr, "system bytes     = %10u\n", (unsigned int) mi.arena);
+      fprintf (stderr, "in use bytes     = %10u\n", (unsigned int) mi.uordblks);
+#if MALLOC_DEBUG > 1
+      if (i > 0)
+        dump_heap (heap_for_ptr (top (ar_ptr)));
+#endif
+      system_b += mi.arena;
+      in_use_b += mi.uordblks;
+      (void) mutex_unlock (&ar_ptr->mutex);
+      ar_ptr = ar_ptr->next;
+      if (ar_ptr == &main_arena)
+        break;
+    }
+  fprintf (stderr, "Total (incl. mmap):\n");
+  fprintf (stderr, "system bytes     = %10u\n", system_b);
+  fprintf (stderr, "in use bytes     = %10u\n", in_use_b);
+  fprintf (stderr, "max mmap regions = %10u\n", (unsigned int) mp_.max_n_mmaps);
+  fprintf (stderr, "max mmap bytes   = %10lu\n",
+           (unsigned long) mp_.max_mmapped_mem);
+  ((_IO_FILE *) stderr)->_flags2 |= old_flags2;
+  _IO_funlockfile (stderr);
+}
+
+
+/*
+   ------------------------------ mallopt ------------------------------
+ */
+
+int
+__libc_mallopt (int param_number, int value)
+{
+  mstate av = &main_arena;
+  int res = 1;
+
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+  (void) mutex_lock (&av->mutex);
+  /* Ensure initialization/consolidation */
+  malloc_consolidate (av);
+
+  LIBC_PROBE (memory_mallopt, 2, param_number, value);
+
+  switch (param_number)
+    {
+    case M_MXFAST:
+      if (value >= 0 && value <= MAX_FAST_SIZE)
+        {
+          LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
+          set_max_fast (value);
+        }
+      else
+        res = 0;
+      break;
+
+    case M_TRIM_THRESHOLD:
+      LIBC_PROBE (memory_mallopt_trim_threshold, 3, value,
+                  mp_.trim_threshold, mp_.no_dyn_threshold);
+      mp_.trim_threshold = value;
+      mp_.no_dyn_threshold = 1;
+      break;
+
+    case M_TOP_PAD:
+      LIBC_PROBE (memory_mallopt_top_pad, 3, value,
+                  mp_.top_pad, mp_.no_dyn_threshold);
+      mp_.top_pad = value;
+      mp_.no_dyn_threshold = 1;
+      break;
+
+    case M_MMAP_THRESHOLD:
+      /* Forbid setting the threshold too high. */
+      if ((unsigned long) value > HEAP_MAX_SIZE / 2)
+        res = 0;
+      else
+        {
+          LIBC_PROBE (memory_mallopt_mmap_threshold, 3, value,
+                      mp_.mmap_threshold, mp_.no_dyn_threshold);
+          mp_.mmap_threshold = value;
+          mp_.no_dyn_threshold = 1;
+        }
+      break;
+
+    case M_MMAP_MAX:
+      LIBC_PROBE (memory_mallopt_mmap_max, 3, value,
+                  mp_.n_mmaps_max, mp_.no_dyn_threshold);
+      mp_.n_mmaps_max = value;
+      mp_.no_dyn_threshold = 1;
+      break;
+
+    case M_CHECK_ACTION:
+      LIBC_PROBE (memory_mallopt_check_action, 2, value, check_action);
+      check_action = value;
+      break;
+
+    case M_PERTURB:
+      LIBC_PROBE (memory_mallopt_perturb, 2, value, perturb_byte);
+      perturb_byte = value;
+      break;
+
+    case M_ARENA_TEST:
+      if (value > 0)
+        {
+          LIBC_PROBE (memory_mallopt_arena_test, 2, value, mp_.arena_test);
+          mp_.arena_test = value;
+        }
+      break;
+
+    case M_ARENA_MAX:
+      if (value > 0)
+        {
+          LIBC_PROBE (memory_mallopt_arena_max, 2, value, mp_.arena_max);
+          mp_.arena_max = value;
+        }
+      break;
+    }
+  (void) mutex_unlock (&av->mutex);
+  return res;
+}
+libc_hidden_def (__libc_mallopt)
+
+
+/*
+   -------------------- Alternative MORECORE functions --------------------
+ */
+
+
+/*
+   General Requirements for MORECORE.
+
+   The MORECORE function must have the following properties:
+
+   If MORECORE_CONTIGUOUS is false:
+
+ * MORECORE must allocate in multiples of pagesize. It will
+      only be called with arguments that are multiples of pagesize.
+
+ * MORECORE(0) must return an address that is at least
+      MALLOC_ALIGNMENT aligned. (Page-aligning always suffices.)
+
+   else (i.e. If MORECORE_CONTIGUOUS is true):
+
+ * Consecutive calls to MORECORE with positive arguments
+      return increasing addresses, indicating that space has been
+      contiguously extended.
+
+ * MORECORE need not allocate in multiples of pagesize.
+      Calls to MORECORE need not have args of multiples of pagesize.
+
+ * MORECORE need not page-align.
+
+   In either case:
+
+ * MORECORE may allocate more memory than requested. (Or even less,
+      but this will generally result in a malloc failure.)
+
+ * MORECORE must not allocate memory when given argument zero, but
+      instead return one past the end address of memory from previous
+      nonzero call. This malloc does NOT call MORECORE(0)
+      until at least one call with positive arguments is made, so
+      the initial value returned is not important.
+
+ * Even though consecutive calls to MORECORE need not return contiguous
+      addresses, it must be OK for malloc'ed chunks to span multiple
+      regions in those cases where they do happen to be contiguous.
+
+ * MORECORE need not handle negative arguments -- it may instead
+      just return MORECORE_FAILURE when given negative arguments.
+      Negative arguments are always multiples of pagesize. MORECORE
+      must not misinterpret negative args as large positive unsigned
+      args. You can suppress all such calls from even occurring by defining
+      MORECORE_CANNOT_TRIM,
+
+   There is some variation across systems about the type of the
+   argument to sbrk/MORECORE. If size_t is unsigned, then it cannot
+   actually be size_t, because sbrk supports negative args, so it is
+   normally the signed type of the same width as size_t (sometimes
+   declared as "intptr_t", and sometimes "ptrdiff_t").  It doesn't much
+   matter though. Internally, we use "long" as arguments, which should
+   work across all reasonable possibilities.
+
+   Additionally, if MORECORE ever returns failure for a positive
+   request, then mmap is used as a noncontiguous system allocator. This
+   is a useful backup strategy for systems with holes in address spaces
+   -- in this case sbrk cannot contiguously expand the heap, but mmap
+   may be able to map noncontiguous space.
+
+   If you'd like mmap to ALWAYS be used, you can define MORECORE to be
+   a function that always returns MORECORE_FAILURE.
+
+   If you are using this malloc with something other than sbrk (or its
+   emulation) to supply memory regions, you probably want to set
+   MORECORE_CONTIGUOUS as false.  As an example, here is a custom
+   allocator kindly contributed for pre-OSX macOS.  It uses virtually
+   but not necessarily physically contiguous non-paged memory (locked
+   in, present and won't get swapped out).  You can use it by
+   uncommenting this section, adding some #includes, and setting up the
+   appropriate defines above:
+
+ *#define MORECORE osMoreCore
+ *#define MORECORE_CONTIGUOUS 0
+
+   There is also a shutdown routine that should somehow be called for
+   cleanup upon program exit.
+
+ *#define MAX_POOL_ENTRIES 100
+ *#define MINIMUM_MORECORE_SIZE  (64 * 1024)
+   static int next_os_pool;
+   void *our_os_pools[MAX_POOL_ENTRIES];
+
+   void *osMoreCore(int size)
+   {
+    void *ptr = 0;
+    static void *sbrk_top = 0;
+
+    if (size > 0)
+    {
+      if (size < MINIMUM_MORECORE_SIZE)
+         size = MINIMUM_MORECORE_SIZE;
+      if (CurrentExecutionLevel() == kTaskLevel)
+         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+      if (ptr == 0)
+      {
+        return (void *) MORECORE_FAILURE;
+      }
+      // save ptrs so they can be freed during cleanup
+      our_os_pools[next_os_pool] = ptr;
+      next_os_pool++;
+      ptr = (void *) ((((unsigned long) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+      sbrk_top = (char *) ptr + size;
+      return ptr;
+    }
+    else if (size < 0)
+    {
+      // we don't currently support shrink behavior
+      return (void *) MORECORE_FAILURE;
+    }
+    else
+    {
+      return sbrk_top;
+    }
+   }
+
+   // cleanup any allocated memory pools
+   // called as last thing before shutting down driver
+
+   void osCleanupMem(void)
+   {
+    void **ptr;
+
+    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+      if (*ptr)
+      {
+         PoolDeallocate(*ptr);
+ * ptr = 0;
+      }
+   }
+
+ */
+
+
+/* Helper code.  */
+
+extern char **__libc_argv attribute_hidden;
+
+static void
+malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
+{
+  /* Avoid using this arena in future.  We do not attempt to synchronize this
+     with anything else because we minimally want to ensure that __libc_message
+     gets its resources safely without stumbling on the current corruption.  */
+  if (ar_ptr)
+    set_arena_corrupt (ar_ptr);
+
+  if ((action & 5) == 5)
+    __libc_message (action & 2, "%s\n", str);
+  else if (action & 1)
+    {
+      char buf[2 * sizeof (uintptr_t) + 1];
+
+      buf[sizeof (buf) - 1] = '\0';
+      char *cp = _itoa_word ((uintptr_t) ptr, &buf[sizeof (buf) - 1], 16, 0);
+      while (cp > buf)
+        *--cp = '0';
+
+      __libc_message (action & 2, "*** Error in `%s': %s: 0x%s ***\n",
+                      __libc_argv[0] ? : "<unknown>", str, cp);
+    }
+  else if (action & 2)
+    abort ();
+}
+
+/* We need a wrapper function for one of the additions of POSIX.  */
+int
+__posix_memalign (void **memptr, size_t alignment, size_t size)
+{
+  void *mem;
+
+  /* Test whether the SIZE argument is valid.  It must be a power of
+     two multiple of sizeof (void *).  */
+  if (alignment % sizeof (void *) != 0
+      || !powerof2 (alignment / sizeof (void *))
+      || alignment == 0)
+    return EINVAL;
+
+
+  void *address = RETURN_ADDRESS (0);
+  mem = _mid_memalign (alignment, size, address);
+
+  if (mem != NULL)
+    {
+      *memptr = mem;
+      return 0;
+    }
+
+  return ENOMEM;
+}
+weak_alias (__posix_memalign, posix_memalign)
+
+
+int
+__malloc_info (int options, FILE *fp)
+{
+  /* For now, at least.  */
+  if (options != 0)
+    return EINVAL;
+
+  int n = 0;
+  size_t total_nblocks = 0;
+  size_t total_nfastblocks = 0;
+  size_t total_avail = 0;
+  size_t total_fastavail = 0;
+  size_t total_system = 0;
+  size_t total_max_system = 0;
+  size_t total_aspace = 0;
+  size_t total_aspace_mprotect = 0;
+
+
+
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  fputs ("<malloc version=\"1\">\n", fp);
+
+  /* Iterate over all arenas currently in use.  */
+  mstate ar_ptr = &main_arena;
+  do
+    {
+      fprintf (fp, "<heap nr=\"%d\">\n<sizes>\n", n++);
+
+      size_t nblocks = 0;
+      size_t nfastblocks = 0;
+      size_t avail = 0;
+      size_t fastavail = 0;
+      struct
+      {
+	size_t from;
+	size_t to;
+	size_t total;
+	size_t count;
+      } sizes[NFASTBINS + NBINS - 1];
+#define nsizes (sizeof (sizes) / sizeof (sizes[0]))
+
+      mutex_lock (&ar_ptr->mutex);
+
+      for (size_t i = 0; i < NFASTBINS; ++i)
+	{
+	  mchunkptr p = fastbin (ar_ptr, i);
+	  if (p != NULL)
+	    {
+	      size_t nthissize = 0;
+	      size_t thissize = chunksize (p);
+
+	      while (p != NULL)
+		{
+		  ++nthissize;
+		  p = p->fd;
+		}
+
+	      fastavail += nthissize * thissize;
+	      nfastblocks += nthissize;
+	      sizes[i].from = thissize - (MALLOC_ALIGNMENT - 1);
+	      sizes[i].to = thissize;
+	      sizes[i].count = nthissize;
+	    }
+	  else
+	    sizes[i].from = sizes[i].to = sizes[i].count = 0;
+
+	  sizes[i].total = sizes[i].count * sizes[i].to;
+	}
+
+
+      mbinptr bin;
+      struct malloc_chunk *r;
+
+      for (size_t i = 1; i < NBINS; ++i)
+	{
+	  bin = bin_at (ar_ptr, i);
+	  r = bin->fd;
+	  sizes[NFASTBINS - 1 + i].from = ~((size_t) 0);
+	  sizes[NFASTBINS - 1 + i].to = sizes[NFASTBINS - 1 + i].total
+					  = sizes[NFASTBINS - 1 + i].count = 0;
+
+	  if (r != NULL)
+	    while (r != bin)
+	      {
+		++sizes[NFASTBINS - 1 + i].count;
+		sizes[NFASTBINS - 1 + i].total += r->size;
+		sizes[NFASTBINS - 1 + i].from
+		  = MIN (sizes[NFASTBINS - 1 + i].from, r->size);
+		sizes[NFASTBINS - 1 + i].to = MAX (sizes[NFASTBINS - 1 + i].to,
+						   r->size);
+
+		r = r->fd;
+	      }
+
+	  if (sizes[NFASTBINS - 1 + i].count == 0)
+	    sizes[NFASTBINS - 1 + i].from = 0;
+	  nblocks += sizes[NFASTBINS - 1 + i].count;
+	  avail += sizes[NFASTBINS - 1 + i].total;
+	}
+
+      mutex_unlock (&ar_ptr->mutex);
+
+      total_nfastblocks += nfastblocks;
+      total_fastavail += fastavail;
+
+      total_nblocks += nblocks;
+      total_avail += avail;
+
+      for (size_t i = 0; i < nsizes; ++i)
+	if (sizes[i].count != 0 && i != NFASTBINS)
+	  fprintf (fp, "							      \
+  <size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
+		   sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
+
+      if (sizes[NFASTBINS].count != 0)
+	fprintf (fp, "\
+  <unsorted from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
+		 sizes[NFASTBINS].from, sizes[NFASTBINS].to,
+		 sizes[NFASTBINS].total, sizes[NFASTBINS].count);
+
+      total_system += ar_ptr->system_mem;
+      total_max_system += ar_ptr->max_system_mem;
+
+      fprintf (fp,
+	       "</sizes>\n<total type=\"fast\" count=\"%zu\" size=\"%zu\"/>\n"
+	       "<total type=\"rest\" count=\"%zu\" size=\"%zu\"/>\n"
+	       "<system type=\"current\" size=\"%zu\"/>\n"
+	       "<system type=\"max\" size=\"%zu\"/>\n",
+	       nfastblocks, fastavail, nblocks, avail,
+	       ar_ptr->system_mem, ar_ptr->max_system_mem);
+
+      if (ar_ptr != &main_arena)
+	{
+	  heap_info *heap = heap_for_ptr (top (ar_ptr));
+	  fprintf (fp,
+		   "<aspace type=\"total\" size=\"%zu\"/>\n"
+		   "<aspace type=\"mprotect\" size=\"%zu\"/>\n",
+		   heap->size, heap->mprotect_size);
+	  total_aspace += heap->size;
+	  total_aspace_mprotect += heap->mprotect_size;
+	}
+      else
+	{
+	  fprintf (fp,
+		   "<aspace type=\"total\" size=\"%zu\"/>\n"
+		   "<aspace type=\"mprotect\" size=\"%zu\"/>\n",
+		   ar_ptr->system_mem, ar_ptr->system_mem);
+	  total_aspace += ar_ptr->system_mem;
+	  total_aspace_mprotect += ar_ptr->system_mem;
+	}
+
+      fputs ("</heap>\n", fp);
+      ar_ptr = ar_ptr->next;
+    }
+  while (ar_ptr != &main_arena);
+
+  fprintf (fp,
+	   "<total type=\"fast\" count=\"%zu\" size=\"%zu\"/>\n"
+	   "<total type=\"rest\" count=\"%zu\" size=\"%zu\"/>\n"
+	   "<total type=\"mmap\" count=\"%d\" size=\"%zu\"/>\n"
+	   "<system type=\"current\" size=\"%zu\"/>\n"
+	   "<system type=\"max\" size=\"%zu\"/>\n"
+	   "<aspace type=\"total\" size=\"%zu\"/>\n"
+	   "<aspace type=\"mprotect\" size=\"%zu\"/>\n"
+	   "</malloc>\n",
+	   total_nfastblocks, total_fastavail, total_nblocks, total_avail,
+	   mp_.n_mmaps, mp_.mmapped_mem,
+	   total_system, total_max_system,
+	   total_aspace, total_aspace_mprotect);
+
+  return 0;
+}
+weak_alias (__malloc_info, malloc_info)
+
+
+strong_alias (__libc_calloc, __calloc) weak_alias (__libc_calloc, calloc)
+strong_alias (__libc_free, __cfree) weak_alias (__libc_free, cfree)
+strong_alias (__libc_free, __free) strong_alias (__libc_free, free)
+strong_alias (__libc_malloc, __malloc) strong_alias (__libc_malloc, malloc)
+strong_alias (__libc_memalign, __memalign)
+weak_alias (__libc_memalign, memalign)
+strong_alias (__libc_realloc, __realloc) strong_alias (__libc_realloc, realloc)
+strong_alias (__libc_valloc, __valloc) weak_alias (__libc_valloc, valloc)
+strong_alias (__libc_pvalloc, __pvalloc) weak_alias (__libc_pvalloc, pvalloc)
+strong_alias (__libc_mallinfo, __mallinfo)
+weak_alias (__libc_mallinfo, mallinfo)
+strong_alias (__libc_mallopt, __mallopt) weak_alias (__libc_mallopt, mallopt)
+
+weak_alias (__malloc_stats, malloc_stats)
+weak_alias (__malloc_usable_size, malloc_usable_size)
+weak_alias (__malloc_trim, malloc_trim)
+weak_alias (__malloc_get_state, malloc_get_state)
+weak_alias (__malloc_set_state, malloc_set_state)
+
+
+/* ------------------------------------------------------------
+   History:
+
+   [see ftp://g.oswego.edu/pub/misc/malloc.c for the history of dlmalloc]
+
+ */
+/*
+ * Local variables:
+ * c-basic-offset: 2
+ * End:
+ */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/malloc.h b/ap/libc/glibc/glibc-2.23/malloc/malloc.h
new file mode 100644
index 0000000..f65e18a
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/malloc.h
@@ -0,0 +1,171 @@
+/* Prototypes and definition for malloc implementation.
+   Copyright (C) 1996-2016 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/>.  */
+
+#ifndef _MALLOC_H
+#define _MALLOC_H 1
+
+#include <features.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#ifdef _LIBC
+# define __MALLOC_HOOK_VOLATILE
+# define __MALLOC_DEPRECATED
+#else
+# define __MALLOC_HOOK_VOLATILE volatile
+# define __MALLOC_DEPRECATED __attribute_deprecated__
+#endif
+
+
+__BEGIN_DECLS
+
+/* Allocate SIZE bytes of memory.  */
+extern void *malloc (size_t __size) __THROW __attribute_malloc__ __wur;
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
+extern void *calloc (size_t __nmemb, size_t __size)
+__THROW __attribute_malloc__ __wur;
+
+/* Re-allocate the previously allocated block in __ptr, making the new
+   block SIZE bytes long.  */
+/* __attribute_malloc__ is not used, because if realloc returns
+   the same pointer that was passed to it, aliasing needs to be allowed
+   between objects pointed by the old and new pointers.  */
+extern void *realloc (void *__ptr, size_t __size)
+__THROW __attribute_warn_unused_result__;
+
+/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
+extern void free (void *__ptr) __THROW;
+
+/* Free a block allocated by `calloc'. */
+extern void cfree (void *__ptr) __THROW;
+
+/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
+extern void *memalign (size_t __alignment, size_t __size)
+__THROW __attribute_malloc__ __wur;
+
+/* Allocate SIZE bytes on a page boundary.  */
+extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur;
+
+/* Equivalent to valloc(minimum-page-that-holds(n)), that is, round up
+   __size to nearest pagesize. */
+extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur;
+
+/* Underlying allocation function; successive calls should return
+   contiguous pieces of memory.  */
+extern void *(*__morecore) (ptrdiff_t __size);
+
+/* Default value of `__morecore'.  */
+extern void *__default_morecore (ptrdiff_t __size)
+__THROW __attribute_malloc__;
+
+/* SVID2/XPG mallinfo structure */
+
+struct mallinfo
+{
+  int arena;    /* non-mmapped space allocated from system */
+  int ordblks;  /* number of free chunks */
+  int smblks;   /* number of fastbin blocks */
+  int hblks;    /* number of mmapped regions */
+  int hblkhd;   /* space in mmapped regions */
+  int usmblks;  /* maximum total allocated space */
+  int fsmblks;  /* space available in freed fastbin blocks */
+  int uordblks; /* total allocated space */
+  int fordblks; /* total free space */
+  int keepcost; /* top-most, releasable (via malloc_trim) space */
+};
+
+/* Returns a copy of the updated current mallinfo. */
+extern struct mallinfo mallinfo (void) __THROW;
+
+/* SVID2/XPG mallopt options */
+#ifndef M_MXFAST
+# define M_MXFAST  1    /* maximum request size for "fastbins" */
+#endif
+#ifndef M_NLBLKS
+# define M_NLBLKS  2    /* UNUSED in this malloc */
+#endif
+#ifndef M_GRAIN
+# define M_GRAIN   3    /* UNUSED in this malloc */
+#endif
+#ifndef M_KEEP
+# define M_KEEP    4    /* UNUSED in this malloc */
+#endif
+
+/* mallopt options that actually do something */
+#define M_TRIM_THRESHOLD    -1
+#define M_TOP_PAD           -2
+#define M_MMAP_THRESHOLD    -3
+#define M_MMAP_MAX          -4
+#define M_CHECK_ACTION      -5
+#define M_PERTURB           -6
+#define M_ARENA_TEST        -7
+#define M_ARENA_MAX         -8
+
+/* General SVID/XPG interface to tunable parameters. */
+extern int mallopt (int __param, int __val) __THROW;
+
+/* Release all but __pad bytes of freed top-most memory back to the
+   system. Return 1 if successful, else 0. */
+extern int malloc_trim (size_t __pad) __THROW;
+
+/* Report the number of usable allocated bytes associated with allocated
+   chunk __ptr. */
+extern size_t malloc_usable_size (void *__ptr) __THROW;
+
+/* Prints brief summary statistics on stderr. */
+extern void malloc_stats (void) __THROW;
+
+/* Output information about state of allocator to stream FP.  */
+extern int malloc_info (int __options, FILE *__fp) __THROW;
+
+/* Record the state of all malloc variables in an opaque data structure. */
+extern void *malloc_get_state (void) __THROW;
+
+/* Restore the state of all malloc variables from data obtained with
+   malloc_get_state(). */
+extern int malloc_set_state (void *__ptr) __THROW;
+
+/* Called once when malloc is initialized; redefining this variable in
+   the application provides the preferred way to set up the hook
+   pointers. */
+extern void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) (void)
+__MALLOC_DEPRECATED;
+/* Hooks for debugging and user-defined versions. */
+extern void (*__MALLOC_HOOK_VOLATILE __free_hook) (void *__ptr,
+                                                   const void *)
+__MALLOC_DEPRECATED;
+extern void *(*__MALLOC_HOOK_VOLATILE __malloc_hook)(size_t __size,
+                                                     const void *)
+__MALLOC_DEPRECATED;
+extern void *(*__MALLOC_HOOK_VOLATILE __realloc_hook)(void *__ptr,
+                                                      size_t __size,
+                                                      const void *)
+__MALLOC_DEPRECATED;
+extern void *(*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t __alignment,
+                                                       size_t __size,
+                                                       const void *)
+__MALLOC_DEPRECATED;
+extern void (*__MALLOC_HOOK_VOLATILE __after_morecore_hook) (void);
+
+/* Activate a standard set of debugging hooks. */
+extern void __malloc_check_init (void) __THROW __MALLOC_DEPRECATED;
+
+
+__END_DECLS
+#endif /* malloc.h */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mallocbug.c b/ap/libc/glibc/glibc-2.23/malloc/mallocbug.c
new file mode 100644
index 0000000..7d19b6f
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mallocbug.c
@@ -0,0 +1,70 @@
+/* Reproduce a GNU malloc bug.  */
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#define size_t unsigned int
+
+/* Defined as global variables to avoid warnings about unused variables.  */
+char *dummy0;
+char *dummy1;
+char *fill_info_table1;
+
+
+int
+main (int argc, char *argv[])
+{
+  char *over_top;
+  size_t over_top_size = 0x3000;
+  char *over_top_dup;
+  size_t over_top_dup_size = 0x7000;
+  char *x;
+  size_t i;
+
+  /* Here's what memory is supposed to look like (hex):
+        size  contents
+        3000  original_info_table, later fill_info_table1
+      3fa000  dummy0
+      3fa000  dummy1
+        6000  info_table_2
+        3000  over_top
+
+   */
+  /* mem: original_info_table */
+  dummy0 = malloc (0x3fa000);
+  /* mem: original_info_table, dummy0 */
+  dummy1 = malloc (0x3fa000);
+  /* mem: free, dummy0, dummy1, info_table_2 */
+  fill_info_table1 = malloc (0x3000);
+  /* mem: fill_info_table1, dummy0, dummy1, info_table_2 */
+
+  x = malloc (0x1000);
+  free (x);
+  /* mem: fill_info_table1, dummy0, dummy1, info_table_2, freexx */
+
+  /* This is what loses; info_table_2 and freexx get combined unbeknownst
+     to mmalloc, and mmalloc puts over_top in a section of memory which
+     is on the free list as part of another block (where info_table_2 had
+     been).  */
+  over_top = malloc (over_top_size);
+  over_top_dup = malloc (over_top_dup_size);
+  memset (over_top, 0, over_top_size);
+  memset (over_top_dup, 1, over_top_dup_size);
+
+  for (i = 0; i < over_top_size; ++i)
+    if (over_top[i] != 0)
+      {
+        printf ("FAIL: malloc expands info table\n");
+        return 0;
+      }
+
+  for (i = 0; i < over_top_dup_size; ++i)
+    if (over_top_dup[i] != 1)
+      {
+        printf ("FAIL: malloc expands info table\n");
+        return 0;
+      }
+
+  printf ("PASS: malloc expands info table\n");
+  return 0;
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mcheck-init.c b/ap/libc/glibc/glibc-2.23/malloc/mcheck-init.c
new file mode 100644
index 0000000..8d63dd3
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mcheck-init.c
@@ -0,0 +1,30 @@
+/* Copyright (C) 1991-2016 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/>.  */
+
+/* The object of this file should be installed as libmcheck.a,
+   so one can do -lmcheck to turn on mcheck.  */
+
+#include <malloc.h>
+#include <mcheck.h>
+
+static void
+turn_on_mcheck (void)
+{
+  mcheck (NULL);
+}
+
+void (*__malloc_initialize_hook) (void) = turn_on_mcheck;
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mcheck.c b/ap/libc/glibc/glibc-2.23/malloc/mcheck.c
new file mode 100644
index 0000000..73491b1
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mcheck.c
@@ -0,0 +1,416 @@
+/* Standard debugging hooks for `malloc'.
+   Copyright (C) 1990-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written May 1989 by Mike Haertel.
+
+   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/>.  */
+
+#ifndef _MALLOC_INTERNAL
+# define _MALLOC_INTERNAL
+# include <malloc.h>
+# include <mcheck.h>
+# include <stdint.h>
+# include <stdio.h>
+# include <libintl.h>
+# include <errno.h>
+#endif
+
+/* Old hook values.  */
+static void (*old_free_hook)(__ptr_t ptr, const __ptr_t);
+static __ptr_t (*old_malloc_hook) (size_t size, const __ptr_t);
+static __ptr_t (*old_memalign_hook) (size_t alignment, size_t size,
+                                     const __ptr_t);
+static __ptr_t (*old_realloc_hook) (__ptr_t ptr, size_t size,
+                                    const __ptr_t);
+
+/* Function to call when something awful happens.  */
+static void (*abortfunc) (enum mcheck_status);
+
+/* Arbitrary magical numbers.  */
+#define MAGICWORD       0xfedabeeb
+#define MAGICFREE       0xd8675309
+#define MAGICBYTE       ((char) 0xd7)
+#define MALLOCFLOOD     ((char) 0x93)
+#define FREEFLOOD       ((char) 0x95)
+
+struct hdr
+{
+  size_t size;                  /* Exact size requested by user.  */
+  unsigned long int magic;      /* Magic number to check header integrity.  */
+  struct hdr *prev;
+  struct hdr *next;
+  __ptr_t block;                /* Real block allocated, for memalign.  */
+  unsigned long int magic2;     /* Extra, keeps us doubleword aligned.  */
+};
+
+/* This is the beginning of the list of all memory blocks allocated.
+   It is only constructed if the pedantic testing is requested.  */
+static struct hdr *root;
+
+static int mcheck_used;
+
+/* Nonzero if pedentic checking of all blocks is requested.  */
+static int pedantic;
+
+#if defined _LIBC || defined STDC_HEADERS || defined USG
+# include <string.h>
+# define flood memset
+#else
+static void flood (__ptr_t, int, size_t);
+static void
+flood (__ptr_t ptr, int val, size_t size)
+{
+  char *cp = ptr;
+  while (size--)
+    *cp++ = val;
+}
+#endif
+
+static enum mcheck_status
+checkhdr (const struct hdr *hdr)
+{
+  enum mcheck_status status;
+
+  if (!mcheck_used)
+    /* Maybe the mcheck used is disabled?  This happens when we find
+       an error and report it.  */
+    return MCHECK_OK;
+
+  switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
+    {
+    default:
+      status = MCHECK_HEAD;
+      break;
+    case MAGICFREE:
+      status = MCHECK_FREE;
+      break;
+    case MAGICWORD:
+      if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+        status = MCHECK_TAIL;
+      else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+        status = MCHECK_HEAD;
+      else
+        status = MCHECK_OK;
+      break;
+    }
+  if (status != MCHECK_OK)
+    {
+      mcheck_used = 0;
+      (*abortfunc) (status);
+      mcheck_used = 1;
+    }
+  return status;
+}
+
+void
+mcheck_check_all (void)
+{
+  /* Walk through all the active blocks and test whether they were tampered
+     with.  */
+  struct hdr *runp = root;
+
+  /* Temporarily turn off the checks.  */
+  pedantic = 0;
+
+  while (runp != NULL)
+    {
+      (void) checkhdr (runp);
+
+      runp = runp->next;
+    }
+
+  /* Turn checks on again.  */
+  pedantic = 1;
+}
+#ifdef _LIBC
+libc_hidden_def (mcheck_check_all)
+#endif
+
+static void
+unlink_blk (struct hdr *ptr)
+{
+  if (ptr->next != NULL)
+    {
+      ptr->next->prev = ptr->prev;
+      ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
+                                      + (uintptr_t) ptr->next->next);
+    }
+  if (ptr->prev != NULL)
+    {
+      ptr->prev->next = ptr->next;
+      ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+                                      + (uintptr_t) ptr->prev->next);
+    }
+  else
+    root = ptr->next;
+}
+
+static void
+link_blk (struct hdr *hdr)
+{
+  hdr->prev = NULL;
+  hdr->next = root;
+  root = hdr;
+  hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+  /* And the next block.  */
+  if (hdr->next != NULL)
+    {
+      hdr->next->prev = hdr;
+      hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+                                      + (uintptr_t) hdr->next->next);
+    }
+}
+static void
+freehook (__ptr_t ptr, const __ptr_t caller)
+{
+  if (pedantic)
+    mcheck_check_all ();
+  if (ptr)
+    {
+      struct hdr *hdr = ((struct hdr *) ptr) - 1;
+      checkhdr (hdr);
+      hdr->magic = MAGICFREE;
+      hdr->magic2 = MAGICFREE;
+      unlink_blk (hdr);
+      hdr->prev = hdr->next = NULL;
+      flood (ptr, FREEFLOOD, hdr->size);
+      ptr = hdr->block;
+    }
+  __free_hook = old_free_hook;
+  if (old_free_hook != NULL)
+    (*old_free_hook)(ptr, caller);
+  else
+    free (ptr);
+  __free_hook = freehook;
+}
+
+static __ptr_t
+mallochook (size_t size, const __ptr_t caller)
+{
+  struct hdr *hdr;
+
+  if (pedantic)
+    mcheck_check_all ();
+
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  __malloc_hook = old_malloc_hook;
+  if (old_malloc_hook != NULL)
+    hdr = (struct hdr *) (*old_malloc_hook)(sizeof (struct hdr) + size + 1,
+                                            caller);
+  else
+    hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
+  __malloc_hook = mallochook;
+  if (hdr == NULL)
+    return NULL;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
+  return (__ptr_t) (hdr + 1);
+}
+
+static __ptr_t
+memalignhook (size_t alignment, size_t size,
+              const __ptr_t caller)
+{
+  struct hdr *hdr;
+  size_t slop;
+  char *block;
+
+  if (pedantic)
+    mcheck_check_all ();
+
+  slop = (sizeof *hdr + alignment - 1) & - alignment;
+
+  if (size > ~((size_t) 0) - (slop + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  __memalign_hook = old_memalign_hook;
+  if (old_memalign_hook != NULL)
+    block = (*old_memalign_hook)(alignment, slop + size + 1, caller);
+  else
+    block = memalign (alignment, slop + size + 1);
+  __memalign_hook = memalignhook;
+  if (block == NULL)
+    return NULL;
+
+  hdr = ((struct hdr *) (block + slop)) - 1;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = (__ptr_t) block;
+  hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
+  return (__ptr_t) (hdr + 1);
+}
+
+static __ptr_t
+reallochook (__ptr_t ptr, size_t size, const __ptr_t caller)
+{
+  if (size == 0)
+    {
+      freehook (ptr, caller);
+      return NULL;
+    }
+
+  struct hdr *hdr;
+  size_t osize;
+
+  if (pedantic)
+    mcheck_check_all ();
+
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  if (ptr)
+    {
+      hdr = ((struct hdr *) ptr) - 1;
+      osize = hdr->size;
+
+      checkhdr (hdr);
+      unlink_blk (hdr);
+      if (size < osize)
+        flood ((char *) ptr + size, FREEFLOOD, osize - size);
+    }
+  else
+    {
+      osize = 0;
+      hdr = NULL;
+    }
+  __free_hook = old_free_hook;
+  __malloc_hook = old_malloc_hook;
+  __memalign_hook = old_memalign_hook;
+  __realloc_hook = old_realloc_hook;
+  if (old_realloc_hook != NULL)
+    hdr = (struct hdr *) (*old_realloc_hook)((__ptr_t) hdr,
+                                             sizeof (struct hdr) + size + 1,
+                                             caller);
+  else
+    hdr = (struct hdr *) realloc ((__ptr_t) hdr,
+                                  sizeof (struct hdr) + size + 1);
+  __free_hook = freehook;
+  __malloc_hook = mallochook;
+  __memalign_hook = memalignhook;
+  __realloc_hook = reallochook;
+  if (hdr == NULL)
+    return NULL;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  if (size > osize)
+    flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
+  return (__ptr_t) (hdr + 1);
+}
+
+__attribute__ ((noreturn))
+static void
+mabort (enum mcheck_status status)
+{
+  const char *msg;
+  switch (status)
+    {
+    case MCHECK_OK:
+      msg = _ ("memory is consistent, library is buggy\n");
+      break;
+    case MCHECK_HEAD:
+      msg = _ ("memory clobbered before allocated block\n");
+      break;
+    case MCHECK_TAIL:
+      msg = _ ("memory clobbered past end of allocated block\n");
+      break;
+    case MCHECK_FREE:
+      msg = _ ("block freed twice\n");
+      break;
+    default:
+      msg = _ ("bogus mcheck_status, library is buggy\n");
+      break;
+    }
+#ifdef _LIBC
+  __libc_fatal (msg);
+#else
+  fprintf (stderr, "mcheck: %s", msg);
+  fflush (stderr);
+  abort ();
+#endif
+}
+
+/* Memory barrier so that GCC does not optimize out the argument.  */
+#define malloc_opt_barrier(x) \
+  ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
+
+int
+mcheck (void (*func) (enum mcheck_status))
+{
+  abortfunc = (func != NULL) ? func : &mabort;
+
+  /* These hooks may not be safely inserted if malloc is already in use.  */
+  if (__malloc_initialized <= 0 && !mcheck_used)
+    {
+      /* We call malloc() once here to ensure it is initialized.  */
+      void *p = malloc (0);
+      /* GCC might optimize out the malloc/free pair without a barrier.  */
+      p = malloc_opt_barrier (p);
+      free (p);
+
+      old_free_hook = __free_hook;
+      __free_hook = freehook;
+      old_malloc_hook = __malloc_hook;
+      __malloc_hook = mallochook;
+      old_memalign_hook = __memalign_hook;
+      __memalign_hook = memalignhook;
+      old_realloc_hook = __realloc_hook;
+      __realloc_hook = reallochook;
+      mcheck_used = 1;
+    }
+
+  return mcheck_used ? 0 : -1;
+}
+#ifdef _LIBC
+libc_hidden_def (mcheck)
+#endif
+
+int
+mcheck_pedantic (void (*func) (enum mcheck_status))
+{
+  int res = mcheck (func);
+  if (res == 0)
+    pedantic = 1;
+  return res;
+}
+
+enum mcheck_status
+mprobe (__ptr_t ptr)
+{
+  return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mcheck.h b/ap/libc/glibc/glibc-2.23/malloc/mcheck.h
new file mode 100644
index 0000000..416fcd6
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mcheck.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 1996-2016 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/>.  */
+
+#ifndef _MCHECK_H
+#define _MCHECK_H       1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* Return values for `mprobe': these are the kinds of inconsistencies that
+   `mcheck' enables detection of.  */
+enum mcheck_status
+{
+  MCHECK_DISABLED = -1,         /* Consistency checking is not turned on.  */
+  MCHECK_OK,                    /* Block is fine.  */
+  MCHECK_FREE,                  /* Block freed twice.  */
+  MCHECK_HEAD,                  /* Memory before the block was clobbered.  */
+  MCHECK_TAIL                   /* Memory after the block was clobbered.  */
+};
+
+
+/* Activate a standard collection of debugging hooks.  This must be called
+   before `malloc' is ever called.  ABORTFUNC is called with an error code
+   (see enum above) when an inconsistency is detected.  If ABORTFUNC is
+   null, the standard function prints on stderr and then calls `abort'.  */
+extern int mcheck (void (*__abortfunc)(enum mcheck_status)) __THROW;
+
+/* Similar to `mcheck' but performs checks for all block whenever one of
+   the memory handling functions is called.  This can be very slow.  */
+extern int mcheck_pedantic (void (*__abortfunc)(enum mcheck_status)) __THROW;
+
+/* Force check of all blocks now.  */
+extern void mcheck_check_all (void);
+
+/* Check for aberrations in a particular malloc'd block.  You must have
+   called `mcheck' already.  These are the same checks that `mcheck' does
+   when you free or reallocate a block.  */
+extern enum mcheck_status mprobe (void *__ptr) __THROW;
+
+/* Activate a standard collection of tracing hooks.  */
+extern void mtrace (void) __THROW;
+extern void muntrace (void) __THROW;
+
+__END_DECLS
+#endif /* mcheck.h */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/memusage.c b/ap/libc/glibc/glibc-2.23/malloc/memusage.c
new file mode 100644
index 0000000..3bf0b9d
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/memusage.c
@@ -0,0 +1,936 @@
+/* Profile heap and stack memory usage of running program.
+   Copyright (C) 1998-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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 <assert.h>
+#include <atomic.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include <memusage.h>
+
+/* Pointer to the real functions.  These are determined used `dlsym'
+   when really needed.  */
+static void *(*mallocp)(size_t);
+static void *(*reallocp) (void *, size_t);
+static void *(*callocp) (size_t, size_t);
+static void (*freep) (void *);
+
+static void *(*mmapp) (void *, size_t, int, int, int, off_t);
+static void *(*mmap64p) (void *, size_t, int, int, int, off64_t);
+static int (*munmapp) (void *, size_t);
+static void *(*mremapp) (void *, size_t, size_t, int, void *);
+
+enum
+{
+  idx_malloc = 0,
+  idx_realloc,
+  idx_calloc,
+  idx_free,
+  idx_mmap_r,
+  idx_mmap_w,
+  idx_mmap_a,
+  idx_mremap,
+  idx_munmap,
+  idx_last
+};
+
+
+struct header
+{
+  size_t length;
+  size_t magic;
+};
+
+#define MAGIC 0xfeedbeaf
+
+
+static memusage_cntr_t calls[idx_last];
+static memusage_cntr_t failed[idx_last];
+static memusage_size_t total[idx_last];
+static memusage_size_t grand_total;
+static memusage_cntr_t histogram[65536 / 16];
+static memusage_cntr_t large;
+static memusage_cntr_t calls_total;
+static memusage_cntr_t inplace;
+static memusage_cntr_t decreasing;
+static memusage_cntr_t realloc_free;
+static memusage_cntr_t inplace_mremap;
+static memusage_cntr_t decreasing_mremap;
+static memusage_size_t current_heap;
+static memusage_size_t peak_use[3];
+static __thread uintptr_t start_sp;
+
+/* A few macros to make the source more readable.  */
+#define peak_heap       peak_use[0]
+#define peak_stack      peak_use[1]
+#define peak_total      peak_use[2]
+
+#define DEFAULT_BUFFER_SIZE     32768
+static size_t buffer_size;
+
+static int fd = -1;
+
+static bool not_me;
+static int initialized;
+static bool trace_mmap;
+extern const char *__progname;
+
+struct entry
+{
+  uint64_t heap;
+  uint64_t stack;
+  uint32_t time_low;
+  uint32_t time_high;
+};
+
+static struct entry buffer[2 * DEFAULT_BUFFER_SIZE];
+static uatomic32_t buffer_cnt;
+static struct entry first;
+
+
+/* Update the global data after a successful function call.  */
+static void
+update_data (struct header *result, size_t len, size_t old_len)
+{
+  if (result != NULL)
+    {
+      /* Record the information we need and mark the block using a
+         magic number.  */
+      result->length = len;
+      result->magic = MAGIC;
+    }
+
+  /* Compute current heap usage and compare it with the maximum value.  */
+  memusage_size_t heap
+    = catomic_exchange_and_add (&current_heap, len - old_len) + len - old_len;
+  catomic_max (&peak_heap, heap);
+
+  /* Compute current stack usage and compare it with the maximum
+     value.  The base stack pointer might not be set if this is not
+     the main thread and it is the first call to any of these
+     functions.  */
+  if (__glibc_unlikely (!start_sp))
+    start_sp = GETSP ();
+
+  uintptr_t sp = GETSP ();
+#ifdef STACK_GROWS_UPWARD
+  /* This can happen in threads where we didn't catch the thread's
+     stack early enough.  */
+  if (__glibc_unlikely (sp < start_sp))
+    start_sp = sp;
+  size_t current_stack = sp - start_sp;
+#else
+  /* This can happen in threads where we didn't catch the thread's
+     stack early enough.  */
+  if (__glibc_unlikely (sp > start_sp))
+    start_sp = sp;
+  size_t current_stack = start_sp - sp;
+#endif
+  catomic_max (&peak_stack, current_stack);
+
+  /* Add up heap and stack usage and compare it with the maximum value.  */
+  catomic_max (&peak_total, heap + current_stack);
+
+  /* Store the value only if we are writing to a file.  */
+  if (fd != -1)
+    {
+      uatomic32_t idx = catomic_exchange_and_add (&buffer_cnt, 1);
+      if (idx + 1 >= 2 * buffer_size)
+        {
+          /* We try to reset the counter to the correct range.  If
+             this fails because of another thread increasing the
+             counter it does not matter since that thread will take
+             care of the correction.  */
+          uatomic32_t reset = (idx + 1) % (2 * buffer_size);
+          catomic_compare_and_exchange_val_acq (&buffer_cnt, reset, idx + 1);
+          if (idx >= 2 * buffer_size)
+            idx = reset - 1;
+        }
+      assert (idx < 2 * DEFAULT_BUFFER_SIZE);
+
+      buffer[idx].heap = current_heap;
+      buffer[idx].stack = current_stack;
+      GETTIME (buffer[idx].time_low, buffer[idx].time_high);
+
+      /* Write out buffer if it is full.  */
+      if (idx + 1 == buffer_size)
+        write (fd, buffer, buffer_size * sizeof (struct entry));
+      else if (idx + 1 == 2 * buffer_size)
+        write (fd, &buffer[buffer_size], buffer_size * sizeof (struct entry));
+    }
+}
+
+
+/* Interrupt handler.  */
+static void
+int_handler (int signo)
+{
+  /* Nothing gets allocated.  Just record the stack pointer position.  */
+  update_data (NULL, 0, 0);
+}
+
+
+/* Find out whether this is the program we are supposed to profile.
+   For this the name in the variable `__progname' must match the one
+   given in the environment variable MEMUSAGE_PROG_NAME.  If the variable
+   is not present every program assumes it should be profiling.
+
+   If this is the program open a file descriptor to the output file.
+   We will write to it whenever the buffer overflows.  The name of the
+   output file is determined by the environment variable MEMUSAGE_OUTPUT.
+
+   If the environment variable MEMUSAGE_BUFFER_SIZE is set its numerical
+   value determines the size of the internal buffer.  The number gives
+   the number of elements in the buffer.  By setting the number to one
+   one effectively selects unbuffered operation.
+
+   If MEMUSAGE_NO_TIMER is not present an alarm handler is installed
+   which at the highest possible frequency records the stack pointer.  */
+static void
+me (void)
+{
+  const char *env = getenv ("MEMUSAGE_PROG_NAME");
+  size_t prog_len = strlen (__progname);
+
+  initialized = -1;
+  mallocp = (void *(*)(size_t))dlsym (RTLD_NEXT, "malloc");
+  reallocp = (void *(*)(void *, size_t))dlsym (RTLD_NEXT, "realloc");
+  callocp = (void *(*)(size_t, size_t))dlsym (RTLD_NEXT, "calloc");
+  freep = (void (*)(void *))dlsym (RTLD_NEXT, "free");
+
+  mmapp = (void *(*)(void *, size_t, int, int, int, off_t))dlsym (RTLD_NEXT,
+                                                                  "mmap");
+  mmap64p =
+    (void *(*)(void *, size_t, int, int, int, off64_t))dlsym (RTLD_NEXT,
+                                                              "mmap64");
+  mremapp = (void *(*)(void *, size_t, size_t, int, void *))dlsym (RTLD_NEXT,
+                                                                   "mremap");
+  munmapp = (int (*)(void *, size_t))dlsym (RTLD_NEXT, "munmap");
+  initialized = 1;
+
+  if (env != NULL)
+    {
+      /* Check for program name.  */
+      size_t len = strlen (env);
+      if (len > prog_len || strcmp (env, &__progname[prog_len - len]) != 0
+          || (prog_len != len && __progname[prog_len - len - 1] != '/'))
+        not_me = true;
+    }
+
+  /* Only open the file if it's really us.  */
+  if (!not_me && fd == -1)
+    {
+      const char *outname;
+
+      if (!start_sp)
+        start_sp = GETSP ();
+
+      outname = getenv ("MEMUSAGE_OUTPUT");
+      if (outname != NULL && outname[0] != '\0'
+          && (access (outname, R_OK | W_OK) == 0 || errno == ENOENT))
+        {
+          fd = creat64 (outname, 0666);
+
+          if (fd == -1)
+            /* Don't do anything in future calls if we cannot write to
+               the output file.  */
+            not_me = true;
+          else
+            {
+              /* Write the first entry.  */
+              first.heap = 0;
+              first.stack = 0;
+              GETTIME (first.time_low, first.time_high);
+              /* Write it two times since we need the starting and end time. */
+              write (fd, &first, sizeof (first));
+              write (fd, &first, sizeof (first));
+
+              /* Determine the buffer size.  We use the default if the
+                 environment variable is not present.  */
+              buffer_size = DEFAULT_BUFFER_SIZE;
+              const char *str_buffer_size = getenv ("MEMUSAGE_BUFFER_SIZE");
+              if (str_buffer_size != NULL)
+                {
+                  buffer_size = atoi (str_buffer_size);
+                  if (buffer_size == 0 || buffer_size > DEFAULT_BUFFER_SIZE)
+                    buffer_size = DEFAULT_BUFFER_SIZE;
+                }
+
+              /* Possibly enable timer-based stack pointer retrieval.  */
+              if (getenv ("MEMUSAGE_NO_TIMER") == NULL)
+                {
+                  struct sigaction act;
+
+                  act.sa_handler = (sighandler_t) &int_handler;
+                  act.sa_flags = SA_RESTART;
+                  sigfillset (&act.sa_mask);
+
+                  if (sigaction (SIGPROF, &act, NULL) >= 0)
+                    {
+                      struct itimerval timer;
+
+                      timer.it_value.tv_sec = 0;
+                      timer.it_value.tv_usec = 1;
+                      timer.it_interval = timer.it_value;
+                      setitimer (ITIMER_PROF, &timer, NULL);
+                    }
+                }
+            }
+        }
+
+      if (!not_me && getenv ("MEMUSAGE_TRACE_MMAP") != NULL)
+        trace_mmap = true;
+    }
+}
+
+
+/* Record the initial stack position.  */
+static void
+__attribute__ ((constructor))
+init (void)
+{
+  start_sp = GETSP ();
+  if (!initialized)
+    me ();
+}
+
+
+/* `malloc' replacement.  We keep track of the memory usage if this is the
+   correct program.  */
+void *
+malloc (size_t len)
+{
+  struct header *result = NULL;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* If this is not the correct program just use the normal function.  */
+  if (not_me)
+    return (*mallocp)(len);
+
+  /* Keep track of number of calls.  */
+  catomic_increment (&calls[idx_malloc]);
+  /* Keep track of total memory consumption for `malloc'.  */
+  catomic_add (&total[idx_malloc], len);
+  /* Keep track of total memory requirement.  */
+  catomic_add (&grand_total, len);
+  /* Remember the size of the request.  */
+  if (len < 65536)
+    catomic_increment (&histogram[len / 16]);
+  else
+    catomic_increment (&large);
+  /* Total number of calls of any of the functions.  */
+  catomic_increment (&calls_total);
+
+  /* Do the real work.  */
+  result = (struct header *) (*mallocp)(len + sizeof (struct header));
+  if (result == NULL)
+    {
+      catomic_increment (&failed[idx_malloc]);
+      return NULL;
+    }
+
+  /* Update the allocation data and write out the records if necessary.  */
+  update_data (result, len, 0);
+
+  /* Return the pointer to the user buffer.  */
+  return (void *) (result + 1);
+}
+
+
+/* `realloc' replacement.  We keep track of the memory usage if this is the
+   correct program.  */
+void *
+realloc (void *old, size_t len)
+{
+  struct header *result = NULL;
+  struct header *real;
+  size_t old_len;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* If this is not the correct program just use the normal function.  */
+  if (not_me)
+    return (*reallocp)(old, len);
+
+  if (old == NULL)
+    {
+      /* This is really a `malloc' call.  */
+      real = NULL;
+      old_len = 0;
+    }
+  else
+    {
+      real = ((struct header *) old) - 1;
+      if (real->magic != MAGIC)
+        /* This is no memory allocated here.  */
+        return (*reallocp)(old, len);
+
+      old_len = real->length;
+    }
+
+  /* Keep track of number of calls.  */
+  catomic_increment (&calls[idx_realloc]);
+  if (len > old_len)
+    {
+      /* Keep track of total memory consumption for `realloc'.  */
+      catomic_add (&total[idx_realloc], len - old_len);
+      /* Keep track of total memory requirement.  */
+      catomic_add (&grand_total, len - old_len);
+    }
+
+  if (len == 0 && old != NULL)
+    {
+      /* Special case.  */
+      catomic_increment (&realloc_free);
+      /* Keep track of total memory freed using `free'.  */
+      catomic_add (&total[idx_free], real->length);
+
+      /* Update the allocation data and write out the records if necessary.  */
+      update_data (NULL, 0, old_len);
+
+      /* Do the real work.  */
+      (*freep) (real);
+
+      return NULL;
+    }
+
+  /* Remember the size of the request.  */
+  if (len < 65536)
+    catomic_increment (&histogram[len / 16]);
+  else
+    catomic_increment (&large);
+  /* Total number of calls of any of the functions.  */
+  catomic_increment (&calls_total);
+
+  /* Do the real work.  */
+  result = (struct header *) (*reallocp)(real, len + sizeof (struct header));
+  if (result == NULL)
+    {
+      catomic_increment (&failed[idx_realloc]);
+      return NULL;
+    }
+
+  /* Record whether the reduction/increase happened in place.  */
+  if (real == result)
+    catomic_increment (&inplace);
+  /* Was the buffer increased?  */
+  if (old_len > len)
+    catomic_increment (&decreasing);
+
+  /* Update the allocation data and write out the records if necessary.  */
+  update_data (result, len, old_len);
+
+  /* Return the pointer to the user buffer.  */
+  return (void *) (result + 1);
+}
+
+
+/* `calloc' replacement.  We keep track of the memory usage if this is the
+   correct program.  */
+void *
+calloc (size_t n, size_t len)
+{
+  struct header *result;
+  size_t size = n * len;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* If this is not the correct program just use the normal function.  */
+  if (not_me)
+    return (*callocp)(n, len);
+
+  /* Keep track of number of calls.  */
+  catomic_increment (&calls[idx_calloc]);
+  /* Keep track of total memory consumption for `calloc'.  */
+  catomic_add (&total[idx_calloc], size);
+  /* Keep track of total memory requirement.  */
+  catomic_add (&grand_total, size);
+  /* Remember the size of the request.  */
+  if (size < 65536)
+    catomic_increment (&histogram[size / 16]);
+  else
+    catomic_increment (&large);
+  /* Total number of calls of any of the functions.  */
+  ++calls_total;
+
+  /* Do the real work.  */
+  result = (struct header *) (*mallocp)(size + sizeof (struct header));
+  if (result == NULL)
+    {
+      catomic_increment (&failed[idx_calloc]);
+      return NULL;
+    }
+
+  /* Update the allocation data and write out the records if necessary.  */
+  update_data (result, size, 0);
+
+  /* Do what `calloc' would have done and return the buffer to the caller.  */
+  return memset (result + 1, '\0', size);
+}
+
+
+/* `free' replacement.  We keep track of the memory usage if this is the
+   correct program.  */
+void
+free (void *ptr)
+{
+  struct header *real;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return;
+
+      me ();
+    }
+
+  /* If this is not the correct program just use the normal function.  */
+  if (not_me)
+    {
+      (*freep) (ptr);
+      return;
+    }
+
+  /* `free (NULL)' has no effect.  */
+  if (ptr == NULL)
+    {
+      catomic_increment (&calls[idx_free]);
+      return;
+    }
+
+  /* Determine the pointer to the header.  */
+  real = ((struct header *) ptr) - 1;
+  if (real->magic != MAGIC)
+    {
+      /* This block wasn't allocated here.  */
+      (*freep) (ptr);
+      return;
+    }
+
+  /* Keep track of number of calls.  */
+  catomic_increment (&calls[idx_free]);
+  /* Keep track of total memory freed using `free'.  */
+  catomic_add (&total[idx_free], real->length);
+
+  /* Update the allocation data and write out the records if necessary.  */
+  update_data (NULL, 0, real->length);
+
+  /* Do the real work.  */
+  (*freep) (real);
+}
+
+
+/* `mmap' replacement.  We do not have to keep track of the size since
+   `munmap' will get it as a parameter.  */
+void *
+mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
+{
+  void *result = NULL;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* Always get a block.  We don't need extra memory.  */
+  result = (*mmapp)(start, len, prot, flags, fd, offset);
+
+  if (!not_me && trace_mmap)
+    {
+      int idx = (flags & MAP_ANON
+                 ? idx_mmap_a : prot & PROT_WRITE ? idx_mmap_w : idx_mmap_r);
+
+      /* Keep track of number of calls.  */
+      catomic_increment (&calls[idx]);
+      /* Keep track of total memory consumption for `malloc'.  */
+      catomic_add (&total[idx], len);
+      /* Keep track of total memory requirement.  */
+      catomic_add (&grand_total, len);
+      /* Remember the size of the request.  */
+      if (len < 65536)
+        catomic_increment (&histogram[len / 16]);
+      else
+        catomic_increment (&large);
+      /* Total number of calls of any of the functions.  */
+      catomic_increment (&calls_total);
+
+      /* Check for failures.  */
+      if (result == NULL)
+        catomic_increment (&failed[idx]);
+      else if (idx == idx_mmap_w)
+        /* Update the allocation data and write out the records if
+           necessary.  Note the first parameter is NULL which means
+           the size is not tracked.  */
+        update_data (NULL, len, 0);
+    }
+
+  /* Return the pointer to the user buffer.  */
+  return result;
+}
+
+
+/* `mmap64' replacement.  We do not have to keep track of the size since
+   `munmap' will get it as a parameter.  */
+void *
+mmap64 (void *start, size_t len, int prot, int flags, int fd, off64_t offset)
+{
+  void *result = NULL;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* Always get a block.  We don't need extra memory.  */
+  result = (*mmap64p)(start, len, prot, flags, fd, offset);
+
+  if (!not_me && trace_mmap)
+    {
+      int idx = (flags & MAP_ANON
+                 ? idx_mmap_a : prot & PROT_WRITE ? idx_mmap_w : idx_mmap_r);
+
+      /* Keep track of number of calls.  */
+      catomic_increment (&calls[idx]);
+      /* Keep track of total memory consumption for `malloc'.  */
+      catomic_add (&total[idx], len);
+      /* Keep track of total memory requirement.  */
+      catomic_add (&grand_total, len);
+      /* Remember the size of the request.  */
+      if (len < 65536)
+        catomic_increment (&histogram[len / 16]);
+      else
+        catomic_increment (&large);
+      /* Total number of calls of any of the functions.  */
+      catomic_increment (&calls_total);
+
+      /* Check for failures.  */
+      if (result == NULL)
+        catomic_increment (&failed[idx]);
+      else if (idx == idx_mmap_w)
+        /* Update the allocation data and write out the records if
+           necessary.  Note the first parameter is NULL which means
+           the size is not tracked.  */
+        update_data (NULL, len, 0);
+    }
+
+  /* Return the pointer to the user buffer.  */
+  return result;
+}
+
+
+/* `mremap' replacement.  We do not have to keep track of the size since
+   `munmap' will get it as a parameter.  */
+void *
+mremap (void *start, size_t old_len, size_t len, int flags, ...)
+{
+  void *result = NULL;
+  va_list ap;
+
+  va_start (ap, flags);
+  void *newaddr = (flags & MREMAP_FIXED) ? va_arg (ap, void *) : NULL;
+  va_end (ap);
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return NULL;
+
+      me ();
+    }
+
+  /* Always get a block.  We don't need extra memory.  */
+  result = (*mremapp)(start, old_len, len, flags, newaddr);
+
+  if (!not_me && trace_mmap)
+    {
+      /* Keep track of number of calls.  */
+      catomic_increment (&calls[idx_mremap]);
+      if (len > old_len)
+        {
+          /* Keep track of total memory consumption for `malloc'.  */
+          catomic_add (&total[idx_mremap], len - old_len);
+          /* Keep track of total memory requirement.  */
+          catomic_add (&grand_total, len - old_len);
+        }
+      /* Remember the size of the request.  */
+      if (len < 65536)
+        catomic_increment (&histogram[len / 16]);
+      else
+        catomic_increment (&large);
+      /* Total number of calls of any of the functions.  */
+      catomic_increment (&calls_total);
+
+      /* Check for failures.  */
+      if (result == NULL)
+        catomic_increment (&failed[idx_mremap]);
+      else
+        {
+          /* Record whether the reduction/increase happened in place.  */
+          if (start == result)
+            catomic_increment (&inplace_mremap);
+          /* Was the buffer increased?  */
+          if (old_len > len)
+            catomic_increment (&decreasing_mremap);
+
+          /* Update the allocation data and write out the records if
+             necessary.  Note the first parameter is NULL which means
+             the size is not tracked.  */
+          update_data (NULL, len, old_len);
+        }
+    }
+
+  /* Return the pointer to the user buffer.  */
+  return result;
+}
+
+
+/* `munmap' replacement.  */
+int
+munmap (void *start, size_t len)
+{
+  int result;
+
+  /* Determine real implementation if not already happened.  */
+  if (__glibc_unlikely (initialized <= 0))
+    {
+      if (initialized == -1)
+        return -1;
+
+      me ();
+    }
+
+  /* Do the real work.  */
+  result = (*munmapp)(start, len);
+
+  if (!not_me && trace_mmap)
+    {
+      /* Keep track of number of calls.  */
+      catomic_increment (&calls[idx_munmap]);
+
+      if (__glibc_likely (result == 0))
+        {
+          /* Keep track of total memory freed using `free'.  */
+          catomic_add (&total[idx_munmap], len);
+
+          /* Update the allocation data and write out the records if
+             necessary.  */
+          update_data (NULL, 0, len);
+        }
+      else
+        catomic_increment (&failed[idx_munmap]);
+    }
+
+  return result;
+}
+
+
+/* Write some statistics to standard error.  */
+static void
+__attribute__ ((destructor))
+dest (void)
+{
+  int percent, cnt;
+  unsigned long int maxcalls;
+
+  /* If we haven't done anything here just return.  */
+  if (not_me)
+    return;
+
+  /* If we should call any of the memory functions don't do any profiling.  */
+  not_me = true;
+
+  /* Finish the output file.  */
+  if (fd != -1)
+    {
+      /* Write the partially filled buffer.  */
+      if (buffer_cnt > buffer_size)
+        write (fd, buffer + buffer_size,
+               (buffer_cnt - buffer_size) * sizeof (struct entry));
+      else
+        write (fd, buffer, buffer_cnt * sizeof (struct entry));
+
+      /* Go back to the beginning of the file.  We allocated two records
+         here when we opened the file.  */
+      lseek (fd, 0, SEEK_SET);
+      /* Write out a record containing the total size.  */
+      first.stack = peak_total;
+      write (fd, &first, sizeof (struct entry));
+      /* Write out another record containing the maximum for heap and
+         stack.  */
+      first.heap = peak_heap;
+      first.stack = peak_stack;
+      GETTIME (first.time_low, first.time_high);
+      write (fd, &first, sizeof (struct entry));
+
+      /* Close the file.  */
+      close (fd);
+      fd = -1;
+    }
+
+  /* Write a colorful statistic.  */
+  fprintf (stderr, "\n\
+\e[01;32mMemory usage summary:\e[0;0m heap total: %llu, heap peak: %lu, stack peak: %lu\n\
+\e[04;34m         total calls   total memory   failed calls\e[0m\n\
+\e[00;34m malloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
+\e[00;34mrealloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m  (nomove:%ld, dec:%ld, free:%ld)\n\
+\e[00;34m calloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
+\e[00;34m   free|\e[0m %10lu   %12llu\n",
+           (unsigned long long int) grand_total, (unsigned long int) peak_heap,
+           (unsigned long int) peak_stack,
+           (unsigned long int) calls[idx_malloc],
+           (unsigned long long int) total[idx_malloc],
+           failed[idx_malloc] ? "\e[01;41m" : "",
+           (unsigned long int) failed[idx_malloc],
+           (unsigned long int) calls[idx_realloc],
+           (unsigned long long int) total[idx_realloc],
+           failed[idx_realloc] ? "\e[01;41m" : "",
+           (unsigned long int) failed[idx_realloc],
+           (unsigned long int) inplace,
+           (unsigned long int) decreasing,
+           (unsigned long int) realloc_free,
+           (unsigned long int) calls[idx_calloc],
+           (unsigned long long int) total[idx_calloc],
+           failed[idx_calloc] ? "\e[01;41m" : "",
+           (unsigned long int) failed[idx_calloc],
+           (unsigned long int) calls[idx_free],
+           (unsigned long long int) total[idx_free]);
+
+  if (trace_mmap)
+    fprintf (stderr, "\
+\e[00;34mmmap(r)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
+\e[00;34mmmap(w)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
+\e[00;34mmmap(a)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
+\e[00;34m mremap|\e[0m %10lu   %12llu   %s%12lu\e[00;00m  (nomove: %ld, dec:%ld)\n\
+\e[00;34m munmap|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n",
+             (unsigned long int) calls[idx_mmap_r],
+             (unsigned long long int) total[idx_mmap_r],
+             failed[idx_mmap_r] ? "\e[01;41m" : "",
+             (unsigned long int) failed[idx_mmap_r],
+             (unsigned long int) calls[idx_mmap_w],
+             (unsigned long long int) total[idx_mmap_w],
+             failed[idx_mmap_w] ? "\e[01;41m" : "",
+             (unsigned long int) failed[idx_mmap_w],
+             (unsigned long int) calls[idx_mmap_a],
+             (unsigned long long int) total[idx_mmap_a],
+             failed[idx_mmap_a] ? "\e[01;41m" : "",
+             (unsigned long int) failed[idx_mmap_a],
+             (unsigned long int) calls[idx_mremap],
+             (unsigned long long int) total[idx_mremap],
+             failed[idx_mremap] ? "\e[01;41m" : "",
+             (unsigned long int) failed[idx_mremap],
+             (unsigned long int) inplace_mremap,
+             (unsigned long int) decreasing_mremap,
+             (unsigned long int) calls[idx_munmap],
+             (unsigned long long int) total[idx_munmap],
+             failed[idx_munmap] ? "\e[01;41m" : "",
+             (unsigned long int) failed[idx_munmap]);
+
+  /* Write out a histoogram of the sizes of the allocations.  */
+  fprintf (stderr, "\e[01;32mHistogram for block sizes:\e[0;0m\n");
+
+  /* Determine the maximum of all calls for each size range.  */
+  maxcalls = large;
+  for (cnt = 0; cnt < 65536; cnt += 16)
+    if (histogram[cnt / 16] > maxcalls)
+      maxcalls = histogram[cnt / 16];
+
+  for (cnt = 0; cnt < 65536; cnt += 16)
+    /* Only write out the nonzero entries.  */
+    if (histogram[cnt / 16] != 0)
+      {
+        percent = (histogram[cnt / 16] * 100) / calls_total;
+        fprintf (stderr, "%5d-%-5d%12lu ", cnt, cnt + 15,
+                 (unsigned long int) histogram[cnt / 16]);
+        if (percent == 0)
+          fputs (" <1% \e[41;37m", stderr);
+        else
+          fprintf (stderr, "%3d%% \e[41;37m", percent);
+
+        /* Draw a bar with a length corresponding to the current
+           percentage.  */
+        percent = (histogram[cnt / 16] * 50) / maxcalls;
+        while (percent-- > 0)
+          fputc ('=', stderr);
+        fputs ("\e[0;0m\n", stderr);
+      }
+
+  if (large != 0)
+    {
+      percent = (large * 100) / calls_total;
+      fprintf (stderr, "   large   %12lu ", (unsigned long int) large);
+      if (percent == 0)
+        fputs (" <1% \e[41;37m", stderr);
+      else
+        fprintf (stderr, "%3d%% \e[41;37m", percent);
+      percent = (large * 50) / maxcalls;
+      while (percent-- > 0)
+        fputc ('=', stderr);
+      fputs ("\e[0;0m\n", stderr);
+    }
+
+  /* Any following malloc/free etc. calls should generate statistics again,
+     because otherwise freeing something that has been malloced before
+     this destructor (including struct header in front of it) wouldn't
+     be properly freed.  */
+  not_me = false;
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/memusage.sh b/ap/libc/glibc/glibc-2.23/malloc/memusage.sh
new file mode 100755
index 0000000..7430f88
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/memusage.sh
@@ -0,0 +1,274 @@
+#! @BASH@
+# Copyright (C) 1999-2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@gnu.org>, 1999.
+
+# 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/>.
+
+memusageso='@SLIBDIR@/libmemusage.so'
+memusagestat='@BINDIR@/memusagestat'
+TEXTDOMAIN=libc
+
+# Print usage message.
+do_usage() {
+  printf >&2 $"Try \`%s --help' or \`%s --usage' for more information.\n" memusage memusage
+  exit 1
+}
+
+# Message for missing argument.
+do_missing_arg() {
+  printf >&2 $"%s: option '%s' requires an argument\n" memusage "$1"
+  do_usage
+}
+
+# Print help message
+do_help() {
+  echo $"Usage: memusage [OPTION]... PROGRAM [PROGRAMOPTION]...
+Profile memory usage of PROGRAM.
+
+   -n,--progname=NAME     Name of the program file to profile
+   -p,--png=FILE          Generate PNG graphic and store it in FILE
+   -d,--data=FILE         Generate binary data file and store it in FILE
+   -u,--unbuffered        Don't buffer output
+   -b,--buffer=SIZE       Collect SIZE entries before writing them out
+      --no-timer          Don't collect additional information through timer
+   -m,--mmap              Also trace mmap & friends
+
+   -?,--help              Print this help and exit
+      --usage             Give a short usage message
+   -V,--version           Print version information and exit
+
+ The following options only apply when generating graphical output:
+   -t,--time-based        Make graph linear in time
+   -T,--total             Also draw graph of total memory use
+      --title=STRING      Use STRING as title of the graph
+   -x,--x-size=SIZE       Make graphic SIZE pixels wide
+   -y,--y-size=SIZE       Make graphic SIZE pixels high
+
+Mandatory arguments to long options are also mandatory for any corresponding
+short options.
+
+"
+  printf $"For bug reporting instructions, please see:\\n%s.\\n" \
+    "@REPORT_BUGS_TO@"
+  exit 0
+}
+
+do_version() {
+  echo 'memusage @PKGVERSION@@VERSION@'
+  printf $"Copyright (C) %s Free Software Foundation, Inc.
+This is free software; see the source for copying conditions.  There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+" "2016"
+  printf $"Written by %s.
+" "Ulrich Drepper"
+  exit 0
+}
+
+# These variables are local
+buffer=
+data=
+memusagestat_args=
+notimer=
+png=
+progname=
+tracemmap=
+
+# Process arguments.  But stop as soon as the program name is found.
+while test $# -gt 0; do
+  case "$1" in
+  -V | --v | --ve | --ver | --vers | --versi | --versio | --version)
+    do_version
+    ;;
+  -\? | --h | --he | --hel | --help)
+    do_help
+    ;;
+  --us | --usa | --usag | --usage)
+    echo $"Syntax: memusage [--data=FILE] [--progname=NAME] [--png=FILE] [--unbuffered]
+	    [--buffer=SIZE] [--no-timer] [--time-based] [--total]
+	    [--title=STRING] [--x-size=SIZE] [--y-size=SIZE]
+	    PROGRAM [PROGRAMOPTION]..."
+    exit 0
+    ;;
+  -n | --pr | --pro | --prog | --progn | --progna | --prognam | --progname)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    progname="$1"
+    ;;
+  --pr=* | --pro=* | --prog=* | --progn=* | --progna=* | --prognam=* | --progname=*)
+    progname=${1##*=}
+    ;;
+  -p | --pn | --png)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    png="$1"
+    ;;
+  --pn=* | --png=*)
+    png=${1##*=}
+    ;;
+  -d | --d | --da | --dat | --data)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    data="$1"
+    ;;
+  --d=* | --da=* | --dat=* | --data=*)
+    data=${1##*=}
+    ;;
+  -u | --un | --unb | --unbu | --unbuf | --unbuff | --unbuffe | --unbuffer | --unbuffere | --unbuffered)
+    buffer=1
+    ;;
+  -b | --b | --bu | --buf | --buff | --buffe | --buffer)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    buffer="$1"
+    ;;
+  --b=* | --bu=* | --buf=* | --buff=* | --buffe=* | --buffer=*)
+    buffer=${1##*=}
+    ;;
+  --n | --no | --no- | --no-t | --no-ti | --no-tim | --no-time | --no-timer)
+    notimer=yes
+    ;;
+  -m | --m | --mm | --mma | --mmap)
+    tracemmap=yes
+    ;;
+  -t | --tim | --time | --time- | --time-b | --time-ba | --time-bas | --time-base | --time-based)
+    memusagestat_args="$memusagestat_args -t"
+    ;;
+  -T | --to | --tot | --tota | --total)
+    memusagestat_args="$memusagestat_args -T"
+    ;;
+  --tit | --titl | --title)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    memusagestat_args="$memusagestat_args -s $1"
+    ;;
+  --tit=* | --titl=* | --title=*)
+    memusagestat_args="$memusagestat_args -s ${1##*=}"
+    ;;
+  -x | --x | --x- | --x-s | --x-si | --x-siz | --x-size)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    memusagestat_args="$memusagestat_args -x $1"
+    ;;
+  --x=* | --x-=* | --x-s=* | --x-si=* | --x-siz=* | --x-size=*)
+    memusagestat_args="$memusagestat_args -x ${1##*=}"
+    ;;
+  -y | --y | --y- | --y-s | --y-si | --y-siz | --y-size)
+    if test $# -eq 1; then
+      do_missing_arg $1
+    fi
+    shift
+    memusagestat_args="$memusagestat_args -y $1"
+    ;;
+  --y=* | --y-=* | --y-s=* | --y-si=* | --y-siz=* | --y-size=*)
+    memusagestat_args="$memusagestat_args -y ${1##*=}"
+    ;;
+  --p | --p=* | --t | --t=* | --ti | --ti=* | --u)
+    echo >&2 $"memusage: option \`${1##*=}' is ambiguous"
+    do_usage
+    ;;
+  --)
+    # Stop processing arguments.
+    shift
+    break
+    ;;
+  --*)
+    echo >&2 $"memusage: unrecognized option \`$1'"
+    do_usage
+    ;;
+  *)
+    # Unknown option.  This means the rest is the program name and parameters.
+    break
+    ;;
+  esac
+  shift
+done
+
+# See whether any arguments are left.
+if test $# -eq 0; then
+  echo >&2 $"No program name given"
+  do_usage
+fi
+
+# This will be in the environment.
+add_env="LD_PRELOAD=$memusageso"
+
+# Generate data file name.
+datafile=
+if test -n "$data"; then
+  datafile="$data"
+elif test -n "$png"; then
+  datafile=$(mktemp -t memusage.XXXXXX) || exit
+  trap 'rm -f "$datafile"; exit 1' HUP INT QUIT TERM PIPE
+fi
+if test -n "$datafile"; then
+  add_env="$add_env MEMUSAGE_OUTPUT=$datafile"
+fi
+
+# Set program name.
+if test -n "$progname"; then
+  add_env="$add_env MEMUSAGE_PROG_NAME=$progname"
+fi
+
+# Set buffer size.
+if test -n "$buffer"; then
+  add_env="$add_env MEMUSAGE_BUFFER_SIZE=$buffer"
+fi
+
+# Disable timers.
+if test -n "$notimer"; then
+  add_env="$add_env MEMUSAGE_NO_TIMER=yes"
+fi
+
+# Trace mmap.
+if test -n "$tracemmap"; then
+  add_env="$add_env MEMUSAGE_TRACE_MMAP=yes"
+fi
+
+# Execute the program itself.
+eval $add_env '"$@"'
+result=$?
+
+# Generate the PNG data file if wanted and there is something to generate
+# it from.
+if test -n "$png" -a -n "$datafile" -a -s "$datafile"; then
+  # Append extension .png if it isn't already there.
+  case $png in
+  *.png) ;;
+  *) png="$png.png" ;;
+  esac
+  $memusagestat $memusagestat_args "$datafile" "$png"
+fi
+
+if test -z "$data" -a -n "$datafile"; then
+  rm -f "$datafile"
+fi
+
+exit $result
+# Local Variables:
+#  mode:ksh
+# End:
diff --git a/ap/libc/glibc/glibc-2.23/malloc/memusagestat.c b/ap/libc/glibc/glibc-2.23/malloc/memusagestat.c
new file mode 100644
index 0000000..7fb65d1
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/memusagestat.c
@@ -0,0 +1,587 @@
+/* Generate graphic from memory profiling data.
+   Copyright (C) 1998-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published
+   by the Free Software Foundation; version 2 of the License, or
+   (at your option) any later version.
+
+   This program 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 General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#define _FILE_OFFSET_BITS 64
+
+#include <argp.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>
+#include <libintl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <gd.h>
+#include <gdfontl.h>
+#include <gdfonts.h>
+
+#include "../version.h"
+#define PACKAGE _libc_intl_domainname
+
+/* Default size of the generated image.  */
+#define XSIZE 800
+#define YSIZE 600
+
+#ifndef N_
+# define N_(Arg) Arg
+#endif
+
+
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { "output", 'o', N_ ("FILE"), 0, N_ ("Name output file") },
+  { "string", 's', N_ ("STRING"), 0, N_ ("Title string used in output graphic") },
+  { "time", 't', NULL, 0, N_ ("\
+Generate output linear to time (default is linear to number of function calls)\
+") },
+  { "total", 'T', NULL, 0,
+    N_ ("Also draw graph for total memory consumption") },
+  { "x-size", 'x', N_ ("VALUE"), 0,
+    N_ ("Make output graphic VALUE pixels wide") },
+  { "y-size", 'y', "VALUE", 0, N_ ("Make output graphic VALUE pixels high") },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program.  */
+static const char doc[] = N_ ("Generate graphic from memory profiling data");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_ ("DATAFILE [OUTFILE]");
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, more_help
+};
+
+
+struct entry
+{
+  uint64_t heap;
+  uint64_t stack;
+  uint32_t time_low;
+  uint32_t time_high;
+};
+
+
+/* Size of the image.  */
+static size_t xsize;
+static size_t ysize;
+
+/* Name of the output file.  */
+static char *outname;
+
+/* Title string for the graphic.  */
+static const char *string;
+
+/* Nonzero if graph should be generated linear in time.  */
+static int time_based;
+
+/* Nonzero if graph to display total use of memory should be drawn as well.  */
+static int also_total = 0;
+
+
+int
+main (int argc, char *argv[])
+{
+  int remaining;
+  const char *inname;
+  gdImagePtr im_out;
+  int grey, blue, red, green, yellow, black;
+  int fd;
+  struct stat st;
+  size_t maxsize_heap;
+  size_t maxsize_stack;
+  size_t maxsize_total;
+  uint64_t total;
+  uint64_t cnt, cnt2;
+  FILE *outfile;
+  char buf[30];
+  size_t last_heap;
+  size_t last_stack;
+  size_t last_total;
+  struct entry headent[2];
+  uint64_t start_time;
+  uint64_t end_time;
+  uint64_t total_time;
+  const char *heap_format, *stack_format;
+  int heap_scale, stack_scale, line;
+
+  outname = NULL;
+  xsize = XSIZE;
+  ysize = YSIZE;
+  string = NULL;
+
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  if (remaining >= argc || remaining + 2 < argc)
+    {
+      argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
+                 program_invocation_short_name);
+      exit (1);
+    }
+
+  inname = argv[remaining++];
+
+  if (remaining < argc)
+    outname = argv[remaining];
+  else if (outname == NULL)
+    {
+      size_t len = strlen (inname);
+      outname = alloca (len + 5);
+      stpcpy (stpcpy (outname, inname), ".png");
+    }
+
+  /* Open for read/write since we try to repair the file in case the
+     application hasn't terminated cleanly.  */
+  fd = open (inname, O_RDWR);
+  if (fd == -1)
+    error (EXIT_FAILURE, errno, "cannot open input file");
+  if (fstat (fd, &st) != 0)
+    {
+      close (fd);
+      error (EXIT_FAILURE, errno, "cannot get size of input file");
+    }
+  /* Test whether the file contains only full records.  */
+  if ((st.st_size % sizeof (struct entry)) != 0
+      /* The file must at least contain the two administrative records.  */
+      || st.st_size < 2 * sizeof (struct entry))
+    {
+      close (fd);
+      error (EXIT_FAILURE, 0, "input file has incorrect size");
+    }
+  /* Compute number of data entries.  */
+  total = st.st_size / sizeof (struct entry) - 2;
+
+  /* Read the administrative information.  */
+  read (fd, headent, sizeof (headent));
+  maxsize_heap = headent[1].heap;
+  maxsize_stack = headent[1].stack;
+  maxsize_total = headent[0].stack;
+
+  if (maxsize_heap == 0 && maxsize_stack == 0)
+    {
+      /* The program aborted before memusage was able to write the
+         information about the maximum heap and stack use.  Repair
+         the file now.  */
+      struct entry next;
+
+      while (1)
+        {
+          if (read (fd, &next, sizeof (next)) == 0)
+            break;
+          if (next.heap > maxsize_heap)
+            maxsize_heap = next.heap;
+          if (next.stack > maxsize_stack)
+            maxsize_stack = next.stack;
+          if (maxsize_heap + maxsize_stack > maxsize_total)
+            maxsize_total = maxsize_heap + maxsize_stack;
+        }
+
+      headent[0].stack = maxsize_total;
+      headent[1].heap = maxsize_heap;
+      headent[1].stack = maxsize_stack;
+      headent[1].time_low = next.time_low;
+      headent[1].time_high = next.time_high;
+
+      /* Write the computed values in the file.  */
+      lseek (fd, 0, SEEK_SET);
+      write (fd, headent, 2 * sizeof (struct entry));
+    }
+
+  if (also_total)
+    {
+      /* We use one scale and since we also draw the total amount of
+         memory used we have to adapt the maximum.  */
+      maxsize_heap = maxsize_total;
+      maxsize_stack = maxsize_total;
+    }
+
+  start_time = ((uint64_t) headent[0].time_high) << 32 | headent[0].time_low;
+  end_time = ((uint64_t) headent[1].time_high) << 32 | headent[1].time_low;
+  total_time = end_time - start_time;
+
+  if (xsize < 100)
+    xsize = 100;
+  if (ysize < 80)
+    ysize = 80;
+
+  /* Create output image with the specified size.  */
+  im_out = gdImageCreate (xsize, ysize);
+
+  /* First color allocated is background.  */
+  grey = gdImageColorAllocate (im_out, 224, 224, 224);
+
+  /* Set transparent color. */
+  gdImageColorTransparent (im_out, grey);
+
+  /* These are all the other colors we need (in the moment).  */
+  red = gdImageColorAllocate (im_out, 255, 0, 0);
+  green = gdImageColorAllocate (im_out, 0, 130, 0);
+  blue = gdImageColorAllocate (im_out, 0, 0, 255);
+  yellow = gdImageColorAllocate (im_out, 154, 205, 50);
+  black = gdImageColorAllocate (im_out, 0, 0, 0);
+
+  gdImageRectangle (im_out, 40, 20, xsize - 40, ysize - 20, blue);
+
+  if (maxsize_heap < 1024)
+    {
+      heap_format = "%Zu";
+      heap_scale = 1;
+    }
+  else if (maxsize_heap < 1024 * 1024 * 100)
+    {
+      heap_format = "%Zuk";
+      heap_scale = 1024;
+    }
+  else
+    {
+      heap_format = "%ZuM";
+      heap_scale = 1024 * 1024;
+    }
+
+  if (maxsize_stack < 1024)
+    {
+      stack_format = "%Zu";
+      stack_scale = 1;
+    }
+  else if (maxsize_stack < 1024 * 1024 * 100)
+    {
+      stack_format = "%Zuk";
+      stack_scale = 1024;
+    }
+  else
+    {
+      stack_format = "%ZuM";
+      stack_scale = 1024 * 1024;
+    }
+
+  gdImageString (im_out, gdFontSmall, 38, ysize - 14, (unsigned char *) "0",
+                 blue);
+  snprintf (buf, sizeof (buf), heap_format, 0);
+  gdImageString (im_out, gdFontSmall, maxsize_heap < 1024 ? 32 : 26,
+                 ysize - 26, (unsigned char *) buf, red);
+  snprintf (buf, sizeof (buf), stack_format, 0);
+  gdImageString (im_out, gdFontSmall, xsize - 37, ysize - 26,
+                 (unsigned char *) buf, green);
+
+  if (string != NULL)
+    gdImageString (im_out, gdFontLarge, (xsize - strlen (string) * 8) / 2,
+                   2, (unsigned char *) string, green);
+
+  gdImageStringUp (im_out, gdFontSmall, 1, ysize / 2 - 10,
+                   (unsigned char *) "allocated", red);
+  gdImageStringUp (im_out, gdFontSmall, 11, ysize / 2 - 10,
+                   (unsigned char *) "memory", red);
+
+  gdImageStringUp (im_out, gdFontSmall, xsize - 39, ysize / 2 - 10,
+                   (unsigned char *) "used", green);
+  gdImageStringUp (im_out, gdFontSmall, xsize - 27, ysize / 2 - 10,
+                   (unsigned char *) "stack", green);
+
+  snprintf (buf, sizeof (buf), heap_format, maxsize_heap / heap_scale);
+  gdImageString (im_out, gdFontSmall, 39 - strlen (buf) * 6, 14,
+                 (unsigned char *) buf, red);
+  snprintf (buf, sizeof (buf), stack_format, maxsize_stack / stack_scale);
+  gdImageString (im_out, gdFontSmall, xsize - 37, 14,
+                 (unsigned char *) buf, green);
+
+  for (line = 1; line <= 3; ++line)
+    {
+      if (maxsize_heap > 0)
+        {
+          cnt = (((ysize - 40) * (maxsize_heap / 4 * line / heap_scale))
+                 / (maxsize_heap / heap_scale));
+          gdImageDashedLine (im_out, 40, ysize - 20 - cnt, xsize - 40,
+                             ysize - 20 - cnt, red);
+          snprintf (buf, sizeof (buf), heap_format,
+                    maxsize_heap / 4 * line / heap_scale);
+          gdImageString (im_out, gdFontSmall, 39 - strlen (buf) * 6,
+                         ysize - 26 - cnt, (unsigned char *) buf, red);
+        }
+      else
+        cnt = 0;
+
+      if (maxsize_stack > 0)
+        cnt2 = (((ysize - 40) * (maxsize_stack / 4 * line / stack_scale))
+                / (maxsize_stack / stack_scale));
+      else
+        cnt2 = 0;
+
+      if (cnt != cnt2)
+        gdImageDashedLine (im_out, 40, ysize - 20 - cnt2, xsize - 40,
+                           ysize - 20 - cnt2, green);
+      snprintf (buf, sizeof (buf), stack_format, maxsize_stack / 4 * line /
+                stack_scale);
+      gdImageString (im_out, gdFontSmall, xsize - 37, ysize - 26 - cnt2,
+                     (unsigned char *) buf, green);
+    }
+
+  snprintf (buf, sizeof (buf), "%llu", (unsigned long long) total);
+  gdImageString (im_out, gdFontSmall, xsize - 50, ysize - 14,
+                 (unsigned char *) buf, blue);
+
+  if (!time_based)
+    {
+      uint64_t previously = start_time;
+
+      gdImageString (im_out, gdFontSmall, 40 + (xsize - 32 * 6 - 80) / 2,
+                     ysize - 12,
+                     (unsigned char *) "# memory handling function calls",
+                     blue);
+
+
+      last_stack = last_heap = last_total = ysize - 20;
+      for (cnt = 1; cnt <= total; ++cnt)
+        {
+          struct entry entry;
+          size_t new[2];
+          uint64_t now;
+
+          read (fd, &entry, sizeof (entry));
+
+          now = ((uint64_t) entry.time_high) << 32 | entry.time_low;
+
+          if ((((previously - start_time) * 100) / total_time) % 10 < 5)
+            gdImageFilledRectangle (im_out,
+                                    40 + ((cnt - 1) * (xsize - 80)) / total,
+                                    ysize - 19,
+                                    39 + (cnt * (xsize - 80)) / total,
+                                    ysize - 14, yellow);
+          previously = now;
+
+          if (also_total && maxsize_heap > 0)
+            {
+              size_t new3;
+
+              new3 = (ysize - 20) - ((((unsigned long long int) (ysize - 40))
+                                      * (entry.heap + entry.stack))
+                                     / maxsize_heap);
+              gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total,
+                           last_total,
+                           40 + ((xsize - 80) * cnt) / total, new3,
+                           black);
+              last_total = new3;
+            }
+
+          if (maxsize_heap > 0)
+            {
+              new[0] = ((ysize - 20)
+                        - ((((unsigned long long int) (ysize - 40))
+                            * entry.heap) / maxsize_heap));
+              gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total,
+                           last_heap, 40 + ((xsize - 80) * cnt) / total,
+                           new[0], red);
+              last_heap = new[0];
+            }
+
+          if (maxsize_stack > 0)
+            {
+              new[1] = ((ysize - 20)
+                        - ((((unsigned long long int) (ysize - 40))
+                            * entry.stack) / maxsize_stack));
+              gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total,
+                           last_stack, 40 + ((xsize - 80) * cnt) / total,
+                           new[1], green);
+              last_stack = new[1];
+            }
+        }
+
+      cnt = 0;
+      while (cnt < total)
+        {
+          gdImageLine (im_out, 40 + ((xsize - 80) * cnt) / total, ysize - 20,
+                       40 + ((xsize - 80) * cnt) / total, ysize - 15, blue);
+          cnt += MAX (1, total / 20);
+        }
+      gdImageLine (im_out, xsize - 40, ysize - 20, xsize - 40, ysize - 15,
+                   blue);
+    }
+  else
+    {
+      uint64_t next_tick = MAX (1, total / 20);
+      size_t last_xpos = 40;
+
+      gdImageString (im_out, gdFontSmall, 40 + (xsize - 39 * 6 - 80) / 2,
+                     ysize - 12,
+                     (unsigned char *) "				      \
+# memory handling function calls / time", blue);
+
+      for (cnt = 0; cnt < 20; cnt += 2)
+        gdImageFilledRectangle (im_out,
+                                40 + (cnt * (xsize - 80)) / 20, ysize - 19,
+                                39 + ((cnt + 1) * (xsize - 80)) / 20,
+                                ysize - 14, yellow);
+
+      last_stack = last_heap = last_total = ysize - 20;
+      for (cnt = 1; cnt <= total; ++cnt)
+        {
+          struct entry entry;
+          size_t new[2];
+          size_t xpos;
+          uint64_t now;
+
+          read (fd, &entry, sizeof (entry));
+
+          now = ((uint64_t) entry.time_high) << 32 | entry.time_low;
+          xpos = 40 + ((xsize - 80) * (now - start_time)) / total_time;
+
+          if (cnt == next_tick)
+            {
+              gdImageLine (im_out, xpos, ysize - 20, xpos, ysize - 15, blue);
+              next_tick += MAX (1, total / 20);
+            }
+
+          if (also_total && maxsize_heap > 0)
+            {
+              size_t new3;
+
+              new3 = (ysize - 20) - ((((unsigned long long int) (ysize - 40))
+                                      * (entry.heap + entry.stack))
+                                     / maxsize_heap);
+              gdImageLine (im_out, last_xpos, last_total, xpos, new3, black);
+              last_total = new3;
+            }
+
+          if (maxsize_heap > 0)
+            {
+              new[0] = ((ysize - 20)
+                        - ((((unsigned long long int) (ysize - 40))
+                            * entry.heap) / maxsize_heap));
+              gdImageLine (im_out, last_xpos, last_heap, xpos, new[0], red);
+              last_heap = new[0];
+            }
+
+          if (maxsize_stack > 0)
+            {
+              new[1] = ((ysize - 20)
+                        - ((((unsigned long long int) (ysize - 40))
+                            * entry.stack) / maxsize_stack));
+              gdImageLine (im_out, last_xpos, last_stack, xpos, new[1],
+                           green);
+              last_stack = new[1];
+            }
+
+          last_xpos = xpos;
+        }
+    }
+
+  /* Write out the result.  */
+  outfile = fopen (outname, "w");
+  if (outfile == NULL)
+    error (EXIT_FAILURE, errno, "cannot open output file");
+
+  gdImagePng (im_out, outfile);
+
+  fclose (outfile);
+
+  gdImageDestroy (im_out);
+
+  return 0;
+}
+
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  switch (key)
+    {
+    case 'o':
+      outname = arg;
+      break;
+    case 's':
+      string = arg;
+      break;
+    case 't':
+      time_based = 1;
+      break;
+    case 'T':
+      also_total = 1;
+      break;
+    case 'x':
+      xsize = atoi (arg);
+      if (xsize == 0)
+        xsize = XSIZE;
+      break;
+    case 'y':
+      ysize = atoi (arg);
+      if (ysize == 0)
+        ysize = XSIZE;
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  char *tp;
+
+  switch (key)
+    {
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      if (asprintf (&tp, gettext ("\
+For bug reporting instructions, please see:\n\
+%s.\n"), REPORT_BUGS_TO) < 0)
+        return NULL;
+
+      return tp;
+
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "memusagestat %s%s\n", PKGVERSION, VERSION);
+  fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "2016");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/morecore.c b/ap/libc/glibc/glibc-2.23/malloc/morecore.c
new file mode 100644
index 0000000..9e069ac
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/morecore.c
@@ -0,0 +1,53 @@
+/* Copyright (C) 1991-2016 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/>.  */
+
+#ifndef _MALLOC_INTERNAL
+# define _MALLOC_INTERNAL
+# include <malloc.h>
+#endif
+
+#ifndef __GNU_LIBRARY__
+# define __sbrk  sbrk
+#endif
+
+#ifdef __GNU_LIBRARY__
+/* It is best not to declare this and cast its result on foreign operating
+   systems with potentially hostile include files.  */
+
+# include <stddef.h>
+# include <stdlib.h>
+extern void *__sbrk (ptrdiff_t increment) __THROW;
+libc_hidden_proto (__sbrk)
+#endif
+
+#ifndef NULL
+# define NULL 0
+#endif
+
+/* Allocate INCREMENT more bytes of data space,
+   and return the start of data space, or NULL on errors.
+   If INCREMENT is negative, shrink data space.  */
+void *
+__default_morecore (ptrdiff_t increment)
+{
+  void *result = (void *) __sbrk (increment);
+  if (result == (void *) -1)
+    return NULL;
+
+  return result;
+}
+libc_hidden_def (__default_morecore)
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mtrace.c b/ap/libc/glibc/glibc-2.23/malloc/mtrace.c
new file mode 100644
index 0000000..501f014
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mtrace.c
@@ -0,0 +1,357 @@
+/* More debugging hooks for `malloc'.
+   Copyright (C) 1991-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+                 Written April 2, 1991 by John Gilmore of Cygnus Support.
+                 Based on mcheck.c by Mike Haertel.
+
+   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/>.  */
+
+#ifndef _MALLOC_INTERNAL
+# define _MALLOC_INTERNAL
+# include <malloc.h>
+# include <mcheck.h>
+# include <libc-lock.h>
+#endif
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <_itoa.h>
+
+#include <libc-internal.h>
+
+#include <libio/iolibio.h>
+#define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
+#define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
+
+#include <kernel-features.h>
+
+#define TRACE_BUFFER_SIZE 512
+
+static FILE *mallstream;
+static const char mallenv[] = "MALLOC_TRACE";
+static char *malloc_trace_buffer;
+
+__libc_lock_define_initialized (static, lock);
+
+/* Address to breakpoint on accesses to... */
+__ptr_t mallwatch;
+
+/* Old hook values.  */
+static void (*tr_old_free_hook) (__ptr_t ptr, const __ptr_t);
+static __ptr_t (*tr_old_malloc_hook) (size_t size, const __ptr_t);
+static __ptr_t (*tr_old_realloc_hook) (__ptr_t ptr, size_t size,
+                                       const __ptr_t);
+static __ptr_t (*tr_old_memalign_hook) (size_t __alignment, size_t __size,
+                                        const __ptr_t);
+
+/* This function is called when the block being alloc'd, realloc'd, or
+   freed has an address matching the variable "mallwatch".  In a debugger,
+   set "mallwatch" to the address of interest, then put a breakpoint on
+   tr_break.  */
+
+extern void tr_break (void) __THROW;
+libc_hidden_proto (tr_break)
+void
+tr_break (void)
+{
+}
+libc_hidden_def (tr_break)
+
+static void internal_function
+tr_where (const __ptr_t caller, Dl_info *info)
+{
+  if (caller != NULL)
+    {
+      if (info != NULL)
+        {
+          char *buf = (char *) "";
+          if (info->dli_sname != NULL)
+            {
+              size_t len = strlen (info->dli_sname);
+              buf = alloca (len + 6 + 2 * sizeof (void *));
+
+              buf[0] = '(';
+              __stpcpy (_fitoa (caller >= (const __ptr_t) info->dli_saddr
+                                ? caller - (const __ptr_t) info->dli_saddr
+                                : (const __ptr_t) info->dli_saddr - caller,
+                                __stpcpy (__mempcpy (buf + 1, info->dli_sname,
+                                                     len),
+                                          caller >= (__ptr_t) info->dli_saddr
+                                          ? "+0x" : "-0x"),
+                                16, 0),
+                        ")");
+            }
+
+          fprintf (mallstream, "@ %s%s%s[%p] ",
+                   info->dli_fname ? : "", info->dli_fname ? ":" : "",
+                   buf, caller);
+        }
+      else
+        fprintf (mallstream, "@ [%p] ", caller);
+    }
+}
+
+static Dl_info *
+lock_and_info (const __ptr_t caller, Dl_info *mem)
+{
+  if (caller == NULL)
+    return NULL;
+
+  Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
+
+  __libc_lock_lock (lock);
+
+  return res;
+}
+
+static void
+tr_freehook (__ptr_t ptr, const __ptr_t caller)
+{
+  if (ptr == NULL)
+    return;
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+  tr_where (caller, info);
+  /* Be sure to print it first.  */
+  fprintf (mallstream, "- %p\n", ptr);
+  if (ptr == mallwatch)
+    {
+      __libc_lock_unlock (lock);
+      tr_break ();
+      __libc_lock_lock (lock);
+    }
+  __free_hook = tr_old_free_hook;
+  if (tr_old_free_hook != NULL)
+    (*tr_old_free_hook)(ptr, caller);
+  else
+    free (ptr);
+  __free_hook = tr_freehook;
+  __libc_lock_unlock (lock);
+}
+
+static __ptr_t
+tr_mallochook (size_t size, const __ptr_t caller)
+{
+  __ptr_t hdr;
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  __malloc_hook = tr_old_malloc_hook;
+  if (tr_old_malloc_hook != NULL)
+    hdr = (__ptr_t) (*tr_old_malloc_hook)(size, caller);
+  else
+    hdr = (__ptr_t) malloc (size);
+  __malloc_hook = tr_mallochook;
+
+  tr_where (caller, info);
+  /* We could be printing a NULL here; that's OK.  */
+  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+
+  __libc_lock_unlock (lock);
+
+  if (hdr == mallwatch)
+    tr_break ();
+
+  return hdr;
+}
+
+static __ptr_t
+tr_reallochook (__ptr_t ptr, size_t size, const __ptr_t caller)
+{
+  __ptr_t hdr;
+
+  if (ptr == mallwatch)
+    tr_break ();
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  __free_hook = tr_old_free_hook;
+  __malloc_hook = tr_old_malloc_hook;
+  __realloc_hook = tr_old_realloc_hook;
+  if (tr_old_realloc_hook != NULL)
+    hdr = (__ptr_t) (*tr_old_realloc_hook)(ptr, size, caller);
+  else
+    hdr = (__ptr_t) realloc (ptr, size);
+  __free_hook = tr_freehook;
+  __malloc_hook = tr_mallochook;
+  __realloc_hook = tr_reallochook;
+
+  tr_where (caller, info);
+  if (hdr == NULL)
+    {
+      if (size != 0)
+        /* Failed realloc.  */
+        fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
+      else
+        fprintf (mallstream, "- %p\n", ptr);
+    }
+  else if (ptr == NULL)
+    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+  else
+    {
+      fprintf (mallstream, "< %p\n", ptr);
+      tr_where (caller, info);
+      fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
+    }
+
+  __libc_lock_unlock (lock);
+
+  if (hdr == mallwatch)
+    tr_break ();
+
+  return hdr;
+}
+
+static __ptr_t
+tr_memalignhook (size_t alignment, size_t size, const __ptr_t caller)
+{
+  __ptr_t hdr;
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  __memalign_hook = tr_old_memalign_hook;
+  __malloc_hook = tr_old_malloc_hook;
+  if (tr_old_memalign_hook != NULL)
+    hdr = (__ptr_t) (*tr_old_memalign_hook)(alignment, size, caller);
+  else
+    hdr = (__ptr_t) memalign (alignment, size);
+  __memalign_hook = tr_memalignhook;
+  __malloc_hook = tr_mallochook;
+
+  tr_where (caller, info);
+  /* We could be printing a NULL here; that's OK.  */
+  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
+
+  __libc_lock_unlock (lock);
+
+  if (hdr == mallwatch)
+    tr_break ();
+
+  return hdr;
+}
+
+
+#ifdef _LIBC
+
+/* This function gets called to make sure all memory the library
+   allocates get freed and so does not irritate the user when studying
+   the mtrace output.  */
+static void __libc_freeres_fn_section
+release_libc_mem (void)
+{
+  /* Only call the free function if we still are running in mtrace mode.  */
+  if (mallstream != NULL)
+    __libc_freeres ();
+}
+#endif
+
+
+/* We enable tracing if either the environment variable MALLOC_TRACE
+   is set, or if the variable mallwatch has been patched to an address
+   that the debugging user wants us to stop on.  When patching mallwatch,
+   don't forget to set a breakpoint on tr_break!  */
+
+void
+mtrace (void)
+{
+#ifdef _LIBC
+  static int added_atexit_handler;
+#endif
+  char *mallfile;
+
+  /* Don't panic if we're called more than once.  */
+  if (mallstream != NULL)
+    return;
+
+#ifdef _LIBC
+  /* When compiling the GNU libc we use the secure getenv function
+     which prevents the misuse in case of SUID or SGID enabled
+     programs.  */
+  mallfile = __libc_secure_getenv (mallenv);
+#else
+  mallfile = getenv (mallenv);
+#endif
+  if (mallfile != NULL || mallwatch != NULL)
+    {
+      char *mtb = malloc (TRACE_BUFFER_SIZE);
+      if (mtb == NULL)
+        return;
+
+      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
+      if (mallstream != NULL)
+        {
+#ifndef __ASSUME_O_CLOEXEC
+          /* Make sure we close the file descriptor on exec.  */
+          int flags = __fcntl (fileno (mallstream), F_GETFD, 0);
+          if (flags >= 0)
+            {
+              flags |= FD_CLOEXEC;
+              __fcntl (fileno (mallstream), F_SETFD, flags);
+            }
+#endif
+          /* Be sure it doesn't malloc its buffer!  */
+          malloc_trace_buffer = mtb;
+          setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+          fprintf (mallstream, "= Start\n");
+          tr_old_free_hook = __free_hook;
+          __free_hook = tr_freehook;
+          tr_old_malloc_hook = __malloc_hook;
+          __malloc_hook = tr_mallochook;
+          tr_old_realloc_hook = __realloc_hook;
+          __realloc_hook = tr_reallochook;
+          tr_old_memalign_hook = __memalign_hook;
+          __memalign_hook = tr_memalignhook;
+#ifdef _LIBC
+          if (!added_atexit_handler)
+            {
+              extern void *__dso_handle __attribute__ ((__weak__));
+              added_atexit_handler = 1;
+              __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
+                            &__dso_handle ? __dso_handle : NULL);
+            }
+#endif
+        }
+      else
+        free (mtb);
+    }
+}
+
+void
+muntrace (void)
+{
+  if (mallstream == NULL)
+    return;
+
+  /* Do the reverse of what done in mtrace: first reset the hooks and
+     MALLSTREAM, and only after that write the trailer and close the
+     file.  */
+  FILE *f = mallstream;
+  mallstream = NULL;
+  __free_hook = tr_old_free_hook;
+  __malloc_hook = tr_old_malloc_hook;
+  __realloc_hook = tr_old_realloc_hook;
+  __memalign_hook = tr_old_memalign_hook;
+
+  fprintf (f, "= End\n");
+  fclose (f);
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/mtrace.pl b/ap/libc/glibc/glibc-2.23/malloc/mtrace.pl
new file mode 100644
index 0000000..3715a7f
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/mtrace.pl
@@ -0,0 +1,237 @@
+#! @PERL@
+eval "exec @PERL@ -S $0 $@"
+    if 0;
+# Copyright (C) 1997-2016 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+# Contributed by Ulrich Drepper <drepper@gnu.org>, 1997.
+# Based on the mtrace.awk script.
+
+# 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/>.
+
+$VERSION = "@VERSION@";
+$PKGVERSION = "@PKGVERSION@";
+$REPORT_BUGS_TO = '@REPORT_BUGS_TO@';
+$progname = $0;
+
+sub usage {
+    print "Usage: mtrace [OPTION]... [Binary] MtraceData\n";
+    print "  --help       print this help, then exit\n";
+    print "  --version    print version number, then exit\n";
+    print "\n";
+    print "For bug reporting instructions, please see:\n";
+    print "$REPORT_BUGS_TO.\n";
+    exit 0;
+}
+
+# We expect two arguments:
+#   #1: the complete path to the binary
+#   #2: the mtrace data filename
+# The usual options are also recognized.
+
+arglist: while (@ARGV) {
+    if ($ARGV[0] eq "--v" || $ARGV[0] eq "--ve" || $ARGV[0] eq "--ver" ||
+	$ARGV[0] eq "--vers" || $ARGV[0] eq "--versi" ||
+	$ARGV[0] eq "--versio" || $ARGV[0] eq "--version") {
+	print "mtrace $PKGVERSION$VERSION\n";
+	print "Copyright (C) 2016 Free Software Foundation, Inc.\n";
+	print "This is free software; see the source for copying conditions.  There is NO\n";
+	print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";
+	print "Written by Ulrich Drepper <drepper\@gnu.org>\n";
+
+	exit 0;
+    } elsif ($ARGV[0] eq "--h" || $ARGV[0] eq "--he" || $ARGV[0] eq "--hel" ||
+	     $ARGV[0] eq "--help") {
+	&usage;
+    } elsif ($ARGV[0] =~ /^-/) {
+	print "$progname: unrecognized option `$ARGV[0]'\n";
+	print "Try `$progname --help' for more information.\n";
+	exit 1;
+    } else {
+	last arglist;
+    }
+}
+
+if ($#ARGV == 0) {
+    $binary="";
+    $data=$ARGV[0];
+} elsif ($#ARGV == 1) {
+    $binary=$ARGV[0];
+    $data=$ARGV[1];
+
+    if ($binary =~ /^.*[\/].*$/) {
+	$prog = $binary;
+    } else {
+	$prog = "./$binary";
+    }
+    if (open (LOCS, "env LD_TRACE_LOADED_OBJECTS=1 $prog |")) {
+	while (<LOCS>) {
+	    chop;
+	    if (/^.*=> (.*) .(0x[0123456789abcdef]*).$/) {
+		$locs{$1} = $2;
+	    }
+	}
+	close (LOCS);
+    }
+} else {
+    die "Wrong number of arguments, run $progname --help for help.";
+}
+
+sub location {
+    my $str = pop(@_);
+    return $str if ($str eq "");
+    if ($str =~ /.*[[](0x[^]]*)]:(.)*/) {
+	my $addr = $1;
+	my $fct = $2;
+	return $cache{$addr} if (exists $cache{$addr});
+	if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) {
+	    my $line = <ADDR>;
+	    chomp $line;
+	    close (ADDR);
+	    if ($line ne '??:0') {
+		$cache{$addr} = $line;
+		return $cache{$addr};
+	    }
+	}
+	$cache{$addr} = $str = "$fct @ $addr";
+    } elsif ($str =~ /^(.*):.*[[](0x[^]]*)]$/) {
+	my $prog = $1;
+	my $addr = $2;
+	my $searchaddr;
+	return $cache{$addr} if (exists $cache{$addr});
+	if ($locs{$prog} ne "") {
+	    $searchaddr = sprintf "%#x", $addr - $locs{$prog};
+	} else {
+	    $searchaddr = $addr;
+	    $prog = $binary;
+	}
+	if ($binary ne "" && open (ADDR, "addr2line -e $prog $searchaddr|")) {
+	    my $line = <ADDR>;
+	    chomp $line;
+	    close (ADDR);
+	    if ($line ne '??:0') {
+		$cache{$addr} = $line;
+		return $cache{$addr};
+	    }
+	}
+	$cache{$addr} = $str = $addr;
+    } elsif ($str =~ /^.*[[](0x[^]]*)]$/) {
+	my $addr = $1;
+	return $cache{$addr} if (exists $cache{$addr});
+	if ($binary ne "" && open (ADDR, "addr2line -e $binary $addr|")) {
+	    my $line = <ADDR>;
+	    chomp $line;
+	    close (ADDR);
+	    if ($line ne '??:0') {
+		$cache{$addr} = $line;
+		return $cache{$addr};
+	    }
+	}
+	$cache{$addr} = $str = $addr;
+    }
+    return $str;
+}
+
+$nr=0;
+open(DATA, "<$data") || die "Cannot open mtrace data file";
+while (<DATA>) {
+    my @cols = split (' ');
+    my $n, $where;
+    if ($cols[0] eq "@") {
+	# We have address and/or function name.
+	$where=$cols[1];
+	$n=2;
+    } else {
+	$where="";
+	$n=0;
+    }
+
+    $allocaddr=$cols[$n + 1];
+    $howmuch=hex($cols[$n + 2]);
+
+    ++$nr;
+    SWITCH: {
+	if ($cols[$n] eq "+") {
+	    if (defined $allocated{$allocaddr}) {
+		printf ("+ %#0@XXX@x Alloc %d duplicate: %s %s\n",
+			hex($allocaddr), $nr, &location($addrwas{$allocaddr}),
+			$where);
+	    } elsif ($allocaddr =~ /^0x/) {
+		$allocated{$allocaddr}=$howmuch;
+		$addrwas{$allocaddr}=$where;
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "-") {
+	    if (defined $allocated{$allocaddr}) {
+		undef $allocated{$allocaddr};
+		undef $addrwas{$allocaddr};
+	    } else {
+		printf ("- %#0@XXX@x Free %d was never alloc'd %s\n",
+			hex($allocaddr), $nr, &location($where));
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "<") {
+	    if (defined $allocated{$allocaddr}) {
+		undef $allocated{$allocaddr};
+		undef $addrwas{$allocaddr};
+	    } else {
+		printf ("- %#0@XXX@x Realloc %d was never alloc'd %s\n",
+			hex($allocaddr), $nr, &location($where));
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq ">") {
+	    if (defined $allocated{$allocaddr}) {
+		printf ("+ %#0@XXX@x Realloc %d duplicate: %#010x %s %s\n",
+			hex($allocaddr), $nr, $allocated{$allocaddr},
+			&location($addrwas{$allocaddr}), &location($where));
+	    } else {
+		$allocated{$allocaddr}=$howmuch;
+		$addrwas{$allocaddr}=$where;
+	    }
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "=") {
+	    # Ignore "= Start".
+	    last SWITCH;
+	}
+	if ($cols[$n] eq "!") {
+	    # Ignore failed realloc for now.
+	    last SWITCH;
+	}
+    }
+}
+close (DATA);
+
+# Now print all remaining entries.
+@addrs= keys %allocated;
+$anything=0;
+if ($#addrs >= 0) {
+    foreach $addr (sort @addrs) {
+	if (defined $allocated{$addr}) {
+	    if ($anything == 0) {
+		print "\nMemory not freed:\n-----------------\n";
+		print ' ' x (@XXX@ - 7), "Address     Size     Caller\n";
+		$anything=1;
+	    }
+	    printf ("%#0@XXX@x %#8x  at %s\n", hex($addr), $allocated{$addr},
+		    &location($addrwas{$addr}));
+	}
+    }
+}
+print "No memory leaks.\n" if ($anything == 0);
+
+exit $anything != 0;
diff --git a/ap/libc/glibc/glibc-2.23/malloc/obstack.c b/ap/libc/glibc/glibc-2.23/malloc/obstack.c
new file mode 100644
index 0000000..c0927bb
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/obstack.c
@@ -0,0 +1,423 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+   Copyright (C) 1988-2016 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/>.  */
+
+
+#ifdef _LIBC
+# include <obstack.h>
+# include <shlib-compat.h>
+#else
+# include <config.h>
+# include "obstack.h"
+#endif
+
+/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
+   incremented whenever callers compiled using an old obstack.h can no
+   longer properly call the functions in this obstack.c.  */
+#define OBSTACK_INTERFACE_VERSION 1
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself, and the installed library
+   supports the same library interface we do.  This code is part of the GNU
+   C Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand 'configure --with-gnu-libc' and omit the object
+   files, it is simpler to just do this in the source for each such file.  */
+
+#include <stdio.h>              /* Random thing to get __GNU_LIBRARY__.  */
+#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
+# include <gnu-versions.h>
+# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#include <stddef.h>
+
+#ifndef ELIDE_CODE
+
+
+# include <stdint.h>
+
+/* Determine default alignment.  */
+union fooround
+{
+  uintmax_t i;
+  long double d;
+  void *p;
+};
+struct fooalign
+{
+  char c;
+  union fooround u;
+};
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+   But in fact it might be less smart and round addresses to as much as
+   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
+enum
+{
+  DEFAULT_ALIGNMENT = offsetof (struct fooalign, u),
+  DEFAULT_ROUNDING = sizeof (union fooround)
+};
+
+/* When we copy a long block of data, this is the unit to do it with.
+   On some machines, copying successive ints does not work;
+   in such a case, redefine COPYING_UNIT to 'long' (if that works)
+   or 'char' as a last resort.  */
+# ifndef COPYING_UNIT
+#  define COPYING_UNIT int
+# endif
+
+
+/* The functions allocating more room by calling 'obstack_chunk_alloc'
+   jump to the handler pointed to by 'obstack_alloc_failed_handler'.
+   This can be set to a user defined function which should either
+   abort gracefully or use longjump - but shouldn't return.  This
+   variable by default points to the internal function
+   'print_and_abort'.  */
+static _Noreturn void print_and_abort (void);
+void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+
+/* Exit value used when 'print_and_abort' is used.  */
+# include <stdlib.h>
+# ifdef _LIBC
+int obstack_exit_failure = EXIT_FAILURE;
+# else
+#  include "exitfail.h"
+#  define obstack_exit_failure exit_failure
+# endif
+
+# ifdef _LIBC
+#  if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+/* A looong time ago (before 1994, anyway; we're not sure) this global variable
+   was used by non-GNU-C macros to avoid multiple evaluation.  The GNU C
+   library still exports it because somebody might use it.  */
+struct obstack *_obstack_compat = 0;
+compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
+#  endif
+# endif
+
+/* Define a macro that either calls functions with the traditional malloc/free
+   calling interface, or calls functions with the mmalloc/mfree interface
+   (that adds an extra first argument), based on the state of use_extra_arg.
+   For free, do not use ?:, since some compilers, like the MIPS compilers,
+   do not allow (expr) ? void : void.  */
+
+# define CALL_CHUNKFUN(h, size) \
+  (((h)->use_extra_arg)							      \
+   ? (*(h)->chunkfun)((h)->extra_arg, (size))				      \
+   : (*(struct _obstack_chunk *(*)(long))(h)->chunkfun)((size)))
+
+# define CALL_FREEFUN(h, old_chunk) \
+  do { \
+      if ((h)->use_extra_arg)						      \
+	(*(h)->freefun)((h)->extra_arg, (old_chunk));			      \
+      else								      \
+	(*(void (*)(void *))(h)->freefun)((old_chunk));			      \
+    } while (0)
+
+
+/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
+   Objects start on multiples of ALIGNMENT (0 means use default).
+   CHUNKFUN is the function to use to allocate chunks,
+   and FREEFUN the function to free them.
+
+   Return nonzero if successful, calls obstack_alloc_failed_handler if
+   allocation fails.  */
+
+int
+_obstack_begin (struct obstack *h,
+		int size, int alignment,
+		void *(*chunkfun) (long),
+		void (*freefun) (void *))
+{
+  struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+	 Use the values for range checking, because if range checking is off,
+	 the extra bytes won't be missed terribly, but if range checking is on
+	 and we used a larger request, a whole extra 4096 bytes would be
+	 allocated.
+
+	 These number are irrelevant to the new GNU malloc.  I suspect it is
+	 less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+		    + 4 + DEFAULT_ROUNDING - 1)
+		   & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun = (struct _obstack_chunk * (*) (void *, long)) chunkfun;
+  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->use_extra_arg = 0;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h->chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+					       alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = 0;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+int
+_obstack_begin_1 (struct obstack *h, int size, int alignment,
+		  void *(*chunkfun) (void *, long),
+		  void (*freefun) (void *, void *),
+		  void *arg)
+{
+  struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+	 Use the values for range checking, because if range checking is off,
+	 the extra bytes won't be missed terribly, but if range checking is on
+	 and we used a larger request, a whole extra 4096 bytes would be
+	 allocated.
+
+	 These number are irrelevant to the new GNU malloc.  I suspect it is
+	 less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+		    + 4 + DEFAULT_ROUNDING - 1)
+		   & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+  h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->extra_arg = arg;
+  h->use_extra_arg = 1;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h->chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+					       alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = 0;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+   on the assumption that LENGTH bytes need to be added
+   to the current object, or a new object of length LENGTH allocated.
+   Copies any partial object from the end of the old chunk
+   to the beginning of the new one.  */
+
+void
+_obstack_newchunk (struct obstack *h, int length)
+{
+  struct _obstack_chunk *old_chunk = h->chunk;
+  struct _obstack_chunk *new_chunk;
+  long new_size;
+  long obj_size = h->next_free - h->object_base;
+  long i;
+  long already;
+  char *object_base;
+
+  /* Compute size for new chunk.  */
+  new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100;
+  if (new_size < h->chunk_size)
+    new_size = h->chunk_size;
+
+  /* Allocate and initialize the new chunk.  */
+  new_chunk = CALL_CHUNKFUN (h, new_size);
+  if (!new_chunk)
+    (*obstack_alloc_failed_handler)();
+  h->chunk = new_chunk;
+  new_chunk->prev = old_chunk;
+  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+  /* Compute an aligned object_base in the new chunk */
+  object_base =
+    __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
+
+  /* Move the existing object to the new chunk.
+     Word at a time is fast and is safe if the object
+     is sufficiently aligned.  */
+  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+    {
+      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+	   i >= 0; i--)
+	((COPYING_UNIT *) object_base)[i]
+	  = ((COPYING_UNIT *) h->object_base)[i];
+      /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+	 but that can cross a page boundary on a machine
+	 which does not do strict alignment for COPYING_UNITS.  */
+      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+    }
+  else
+    already = 0;
+  /* Copy remaining bytes one by one.  */
+  for (i = already; i < obj_size; i++)
+    object_base[i] = h->object_base[i];
+
+  /* If the object just copied was the only data in OLD_CHUNK,
+     free that chunk and remove it from the chain.
+     But not if that chunk might contain an empty object.  */
+  if (!h->maybe_empty_object
+      && (h->object_base
+	  == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
+			  h->alignment_mask)))
+    {
+      new_chunk->prev = old_chunk->prev;
+      CALL_FREEFUN (h, old_chunk);
+    }
+
+  h->object_base = object_base;
+  h->next_free = h->object_base + obj_size;
+  /* The new chunk certainly contains no empty object yet.  */
+  h->maybe_empty_object = 0;
+}
+# ifdef _LIBC
+libc_hidden_def (_obstack_newchunk)
+# endif
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+   This is here for debugging.
+   If you use it in a program, you are probably losing.  */
+
+/* Suppress -Wmissing-prototypes warning.  We don't want to declare this in
+   obstack.h because it is just for debugging.  */
+int _obstack_allocated_p (struct obstack *h, void *obj) __attribute_pure__;
+
+int
+_obstack_allocated_p (struct obstack *h, void *obj)
+{
+  struct _obstack_chunk *lp;    /* below addr of any objects in this chunk */
+  struct _obstack_chunk *plp;   /* point to previous chunk if any */
+
+  lp = (h)->chunk;
+  /* We use >= rather than > since the object cannot be exactly at
+     the beginning of the chunk but might be an empty object exactly
+     at the end of an adjacent chunk.  */
+  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      lp = plp;
+    }
+  return lp != 0;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+   more recently than OBJ.  If OBJ is zero, free everything in H.  */
+
+# undef obstack_free
+
+void
+__obstack_free (struct obstack *h, void *obj)
+{
+  struct _obstack_chunk *lp;    /* below addr of any objects in this chunk */
+  struct _obstack_chunk *plp;   /* point to previous chunk if any */
+
+  lp = h->chunk;
+  /* We use >= because there cannot be an object at the beginning of a chunk.
+     But there can be an empty object at that address
+     at the end of another chunk.  */
+  while (lp != 0 && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      CALL_FREEFUN (h, lp);
+      lp = plp;
+      /* If we switch chunks, we can't tell whether the new current
+	 chunk contains an empty object, so assume that it may.  */
+      h->maybe_empty_object = 1;
+    }
+  if (lp)
+    {
+      h->object_base = h->next_free = (char *) (obj);
+      h->chunk_limit = lp->limit;
+      h->chunk = lp;
+    }
+  else if (obj != 0)
+    /* obj is not in any of the chunks! */
+    abort ();
+}
+
+# ifdef _LIBC
+/* Older versions of libc used a function _obstack_free intended to be
+   called by non-GCC compilers.  */
+strong_alias (obstack_free, _obstack_free)
+# endif
+
+int
+_obstack_memory_used (struct obstack *h)
+{
+  struct _obstack_chunk *lp;
+  int nbytes = 0;
+
+  for (lp = h->chunk; lp != 0; lp = lp->prev)
+    {
+      nbytes += lp->limit - (char *) lp;
+    }
+  return nbytes;
+}
+
+/* Define the error handler.  */
+# ifdef _LIBC
+#  include <libintl.h>
+# else
+#  include "gettext.h"
+# endif
+# ifndef _
+#  define _(msgid) gettext (msgid)
+# endif
+
+# ifdef _LIBC
+#  include <libio/iolibio.h>
+# endif
+
+static _Noreturn void
+print_and_abort (void)
+{
+  /* Don't change any of these strings.  Yes, it would be possible to add
+     the newline to the string and use fputs or so.  But this must not
+     happen because the "memory exhausted" message appears in other places
+     like this and the translation should be reused instead of creating
+     a very similar string which requires a separate translation.  */
+# ifdef _LIBC
+  (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
+# else
+  fprintf (stderr, "%s\n", _("memory exhausted"));
+# endif
+  exit (obstack_exit_failure);
+}
+
+#endif  /* !ELIDE_CODE */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/obstack.h b/ap/libc/glibc/glibc-2.23/malloc/obstack.h
new file mode 100644
index 0000000..5716202
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/obstack.h
@@ -0,0 +1,515 @@
+/* obstack.h - object stack macros
+   Copyright (C) 1988-2016 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/>.  */
+
+/* Summary:
+
+   All the apparent functions defined here are macros. The idea
+   is that you would use these pre-tested macros to solve a
+   very specific set of problems, and they would run fast.
+   Caution: no side-effects in arguments please!! They may be
+   evaluated MANY times!!
+
+   These macros operate a stack of objects.  Each object starts life
+   small, and may grow to maturity.  (Consider building a word syllable
+   by syllable.)  An object can move while it is growing.  Once it has
+   been "finished" it never changes address again.  So the "top of the
+   stack" is typically an immature growing object, while the rest of the
+   stack is of mature, fixed size and fixed address objects.
+
+   These routines grab large chunks of memory, using a function you
+   supply, called 'obstack_chunk_alloc'.  On occasion, they free chunks,
+   by calling 'obstack_chunk_free'.  You must define them and declare
+   them before using any obstack macros.
+
+   Each independent stack is represented by a 'struct obstack'.
+   Each of the obstack macros expects a pointer to such a structure
+   as the first argument.
+
+   One motivation for this package is the problem of growing char strings
+   in symbol tables.  Unless you are "fascist pig with a read-only mind"
+   --Gosper's immortal quote from HAKMEM item 154, out of context--you
+   would not like to put any arbitrary upper limit on the length of your
+   symbols.
+
+   In practice this often means you will build many short symbols and a
+   few long symbols.  At the time you are reading a symbol you don't know
+   how long it is.  One traditional method is to read a symbol into a
+   buffer, realloc()ating the buffer every time you try to read a symbol
+   that is longer than the buffer.  This is beaut, but you still will
+   want to copy the symbol from the buffer to a more permanent
+   symbol-table entry say about half the time.
+
+   With obstacks, you can work differently.  Use one obstack for all symbol
+   names.  As you read a symbol, grow the name in the obstack gradually.
+   When the name is complete, finalize it.  Then, if the symbol exists already,
+   free the newly read name.
+
+   The way we do this is to take a large chunk, allocating memory from
+   low addresses.  When you want to build a symbol in the chunk you just
+   add chars above the current "high water mark" in the chunk.  When you
+   have finished adding chars, because you got to the end of the symbol,
+   you know how long the chars are, and you can create a new object.
+   Mostly the chars will not burst over the highest address of the chunk,
+   because you would typically expect a chunk to be (say) 100 times as
+   long as an average object.
+
+   In case that isn't clear, when we have enough chars to make up
+   the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+   so we just point to it where it lies.  No moving of chars is
+   needed and this is the second win: potentially long strings need
+   never be explicitly shuffled. Once an object is formed, it does not
+   change its address during its lifetime.
+
+   When the chars burst over a chunk boundary, we allocate a larger
+   chunk, and then copy the partly formed object from the end of the old
+   chunk to the beginning of the new larger chunk.  We then carry on
+   accreting characters to the end of the object as we normally would.
+
+   A special macro is provided to add a single char at a time to a
+   growing object.  This allows the use of register variables, which
+   break the ordinary 'growth' macro.
+
+   Summary:
+	We allocate large chunks.
+	We carve out one object at a time from the current chunk.
+	Once carved, an object never moves.
+	We are free to append data of any size to the currently
+	  growing object.
+	Exactly one object is growing in an obstack at any one time.
+	You can run one obstack per control block.
+	You may have as many control blocks as you dare.
+	Because of the way we do it, you can "unwind" an obstack
+	  back to a previous state. (You may remove objects much
+	  as you would with a stack.)
+ */
+
+
+/* Don't do the contents of this file more than once.  */
+
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+/* We need the type of a pointer subtraction.  If __PTRDIFF_TYPE__ is
+   defined, as with GNU C, use that; that way we don't pollute the
+   namespace with <stddef.h>'s symbols.  Otherwise, include <stddef.h>
+   and use ptrdiff_t.  */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+#endif
+
+/* If B is the base of an object addressed by P, return the result of
+   aligning P to the next multiple of A + 1.  B and P must be of type
+   char *.  A + 1 must be a power of 2.  */
+
+#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
+
+/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
+   where pointers can be converted to integers, aligned as integers,
+   and converted back again.  If PTR_INT_TYPE is narrower than a
+   pointer (e.g., the AS/400), play it safe and compute the alignment
+   relative to B.  Otherwise, use the faster strategy of computing the
+   alignment relative to 0.  */
+
+#define __PTR_ALIGN(B, P, A)						      \
+  __BPTR_ALIGN (sizeof (PTR_INT_TYPE) < sizeof (void *) ? (B) : (char *) 0, \
+		P, A)
+
+#include <string.h>
+
+#ifndef __attribute_pure__
+# define __attribute_pure__ _GL_ATTRIBUTE_PURE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _obstack_chunk           /* Lives at front of each chunk. */
+{
+  char *limit;                  /* 1 past end of this chunk */
+  struct _obstack_chunk *prev;  /* address of prior chunk or NULL */
+  char contents[4];             /* objects begin here */
+};
+
+struct obstack          /* control current object in current chunk */
+{
+  long chunk_size;              /* preferred size to allocate chunks in */
+  struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */
+  char *object_base;            /* address of object we are building */
+  char *next_free;              /* where to add next char to current object */
+  char *chunk_limit;            /* address of char after current chunk */
+  union
+  {
+    PTR_INT_TYPE tempint;
+    void *tempptr;
+  } temp;                       /* Temporary for some macros.  */
+  int alignment_mask;           /* Mask of alignment for each object. */
+  /* These prototypes vary based on 'use_extra_arg', and we use
+     casts to the prototypeless function type in all assignments,
+     but having prototypes here quiets -Wstrict-prototypes.  */
+  struct _obstack_chunk *(*chunkfun) (void *, long);
+  void (*freefun) (void *, struct _obstack_chunk *);
+  void *extra_arg;              /* first arg for chunk alloc/dealloc funcs */
+  unsigned use_extra_arg : 1;     /* chunk alloc/dealloc funcs take extra arg */
+  unsigned maybe_empty_object : 1; /* There is a possibility that the current
+				      chunk contains a zero-length object.  This
+				      prevents freeing the chunk if we allocate
+				      a bigger chunk to replace it. */
+  unsigned alloc_failed : 1;      /* No longer used, as we now call the failed
+				     handler on error, but retained for binary
+				     compatibility.  */
+};
+
+/* Declare the external functions we use; they are in obstack.c.  */
+
+extern void _obstack_newchunk (struct obstack *, int);
+extern int _obstack_begin (struct obstack *, int, int,
+			   void *(*)(long), void (*)(void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+			     void *(*)(void *, long),
+			     void (*)(void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *) __attribute_pure__;
+
+/* The default name of the function for freeing a chunk is 'obstack_free',
+   but gnulib users can override this by defining '__obstack_free'.  */
+#ifndef __obstack_free
+# define __obstack_free obstack_free
+#endif
+extern void __obstack_free (struct obstack *, void *);
+
+
+/* Error handler called when 'obstack_chunk_alloc' failed to allocate
+   more memory.  This can be set to a user defined function which
+   should either abort gracefully or use longjump - but shouldn't
+   return.  The default action is to print a message and abort.  */
+extern void (*obstack_alloc_failed_handler) (void);
+
+/* Exit value used when 'print_and_abort' is used.  */
+extern int obstack_exit_failure;
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+   Note that this might not be the final address of the object
+   because a new chunk might be needed to hold the final size.  */
+
+#define obstack_base(h) ((void *) (h)->object_base)
+
+/* Size for allocating ordinary chunks.  */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk.  */
+
+#define obstack_next_free(h)    ((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object.  */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list.  */
+#define obstack_init(h)							      \
+  _obstack_begin ((h), 0, 0,						      \
+		  (void *(*)(long))obstack_chunk_alloc,			      \
+		  (void (*)(void *))obstack_chunk_free)
+
+#define obstack_begin(h, size)						      \
+  _obstack_begin ((h), (size), 0,					      \
+		  (void *(*)(long))obstack_chunk_alloc,			      \
+		  (void (*)(void *))obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)  \
+  _obstack_begin ((h), (size), (alignment),				      \
+		  (void *(*)(long))(chunkfun),				      \
+		  (void (*)(void *))(freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+  _obstack_begin_1 ((h), (size), (alignment),				      \
+		    (void *(*)(void *, long))(chunkfun),		      \
+		    (void (*)(void *, void *))(freefun), (arg))
+
+#define obstack_chunkfun(h, newchunkfun) \
+  ((h)->chunkfun = (struct _obstack_chunk *(*)(void *, long))(newchunkfun))
+
+#define obstack_freefun(h, newfreefun) \
+  ((h)->freefun = (void (*)(void *, struct _obstack_chunk *))(newfreefun))
+
+#define obstack_1grow_fast(h, achar) (*((h)->next_free)++ = (achar))
+
+#define obstack_blank_fast(h, n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
+
+#if defined __GNUC__
+# if ! (2 < __GNUC__ + (8 <= __GNUC_MINOR__))
+#  define __extension__
+# endif
+
+/* For GNU C, if not -traditional,
+   we can define these macros to compute all args only once
+   without using a global variable.
+   Also, we can avoid using the 'temp' slot, to make faster code.  */
+
+# define obstack_object_size(OBSTACK)					      \
+  __extension__								      \
+    ({ struct obstack const *__o = (OBSTACK);				      \
+       (unsigned) (__o->next_free - __o->object_base); })
+
+# define obstack_room(OBSTACK)						      \
+  __extension__								      \
+    ({ struct obstack const *__o = (OBSTACK);				      \
+       (unsigned) (__o->chunk_limit - __o->next_free); })
+
+# define obstack_make_room(OBSTACK, length)				      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       int __len = (length);						      \
+       if (__o->chunk_limit - __o->next_free < __len)			      \
+	 _obstack_newchunk (__o, __len);				      \
+       (void) 0; })
+
+# define obstack_empty_p(OBSTACK)					      \
+  __extension__								      \
+    ({ struct obstack const *__o = (OBSTACK);				      \
+       (__o->chunk->prev == 0						      \
+	&& __o->next_free == __PTR_ALIGN ((char *) __o->chunk,		      \
+					  __o->chunk->contents,		      \
+					  __o->alignment_mask)); })
+
+# define obstack_grow(OBSTACK, where, length)				      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       int __len = (length);						      \
+       if (__o->next_free + __len > __o->chunk_limit)			      \
+	 _obstack_newchunk (__o, __len);				      \
+       memcpy (__o->next_free, where, __len);				      \
+       __o->next_free += __len;						      \
+       (void) 0; })
+
+# define obstack_grow0(OBSTACK, where, length)				      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       int __len = (length);						      \
+       if (__o->next_free + __len + 1 > __o->chunk_limit)		      \
+	 _obstack_newchunk (__o, __len + 1);				      \
+       memcpy (__o->next_free, where, __len);				      \
+       __o->next_free += __len;						      \
+       *(__o->next_free)++ = 0;						      \
+       (void) 0; })
+
+# define obstack_1grow(OBSTACK, datum)					      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       if (__o->next_free + 1 > __o->chunk_limit)			      \
+	 _obstack_newchunk (__o, 1);					      \
+       obstack_1grow_fast (__o, datum);					      \
+       (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers
+   or ints, and that the data added so far to the current object
+   shares that much alignment.  */
+
+# define obstack_ptr_grow(OBSTACK, datum)				      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       if (__o->next_free + sizeof (void *) > __o->chunk_limit)		      \
+	 _obstack_newchunk (__o, sizeof (void *));			      \
+       obstack_ptr_grow_fast (__o, datum); })				      \
+
+# define obstack_int_grow(OBSTACK, datum)				      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       if (__o->next_free + sizeof (int) > __o->chunk_limit)		      \
+	 _obstack_newchunk (__o, sizeof (int));				      \
+       obstack_int_grow_fast (__o, datum); })
+
+# define obstack_ptr_grow_fast(OBSTACK, aptr)				      \
+  __extension__								      \
+    ({ struct obstack *__o1 = (OBSTACK);				      \
+       void *__p1 = __o1->next_free;					      \
+       *(const void **) __p1 = (aptr);					      \
+       __o1->next_free += sizeof (const void *);			      \
+       (void) 0; })
+
+# define obstack_int_grow_fast(OBSTACK, aint)				      \
+  __extension__								      \
+    ({ struct obstack *__o1 = (OBSTACK);				      \
+       void *__p1 = __o1->next_free;					      \
+       *(int *) __p1 = (aint);						      \
+       __o1->next_free += sizeof (int);					      \
+       (void) 0; })
+
+# define obstack_blank(OBSTACK, length)					      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       int __len = (length);						      \
+       if (__o->chunk_limit - __o->next_free < __len)			      \
+	 _obstack_newchunk (__o, __len);				      \
+       obstack_blank_fast (__o, __len);					      \
+       (void) 0; })
+
+# define obstack_alloc(OBSTACK, length)					      \
+  __extension__								      \
+    ({ struct obstack *__h = (OBSTACK);					      \
+       obstack_blank (__h, (length));					      \
+       obstack_finish (__h); })
+
+# define obstack_copy(OBSTACK, where, length)				      \
+  __extension__								      \
+    ({ struct obstack *__h = (OBSTACK);					      \
+       obstack_grow (__h, (where), (length));				      \
+       obstack_finish (__h); })
+
+# define obstack_copy0(OBSTACK, where, length)				      \
+  __extension__								      \
+    ({ struct obstack *__h = (OBSTACK);					      \
+       obstack_grow0 (__h, (where), (length));				      \
+       obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+   when obstack_blank is called.  */
+# define obstack_finish(OBSTACK)					      \
+  __extension__								      \
+    ({ struct obstack *__o1 = (OBSTACK);				      \
+       void *__value = (void *) __o1->object_base;			      \
+       if (__o1->next_free == __value)					      \
+	 __o1->maybe_empty_object = 1;					      \
+       __o1->next_free							      \
+	 = __PTR_ALIGN (__o1->object_base, __o1->next_free,		      \
+			__o1->alignment_mask);				      \
+       if (__o1->next_free - (char *) __o1->chunk			      \
+	   > __o1->chunk_limit - (char *) __o1->chunk)			      \
+	 __o1->next_free = __o1->chunk_limit;				      \
+       __o1->object_base = __o1->next_free;				      \
+       __value; })
+
+# define obstack_free(OBSTACK, OBJ)					      \
+  __extension__								      \
+    ({ struct obstack *__o = (OBSTACK);					      \
+       void *__obj = (OBJ);						      \
+       if (__obj > (void *) __o->chunk && __obj < (void *) __o->chunk_limit)  \
+	 __o->next_free = __o->object_base = (char *) __obj;		      \
+       else (__obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ */
+
+# define obstack_object_size(h) \
+  (unsigned) ((h)->next_free - (h)->object_base)
+
+# define obstack_room(h)						      \
+  (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+  ((h)->chunk->prev == 0						      \
+   && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk,		      \
+				     (h)->chunk->contents,		      \
+				     (h)->alignment_mask))
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+   so that we can avoid having void expressions
+   in the arms of the conditional expression.
+   Casting the third operand to void was tried before,
+   but some compilers won't accept it.  */
+
+# define obstack_make_room(h, length)					      \
+  ((h)->temp.tempint = (length),					      \
+   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)		      \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
+
+# define obstack_grow(h, where, length)					      \
+  ((h)->temp.tempint = (length),					      \
+   (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)		      \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),		      \
+   memcpy ((h)->next_free, where, (h)->temp.tempint),			      \
+   (h)->next_free += (h)->temp.tempint)
+
+# define obstack_grow0(h, where, length)				      \
+  ((h)->temp.tempint = (length),					      \
+   (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit)		      \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0),		      \
+   memcpy ((h)->next_free, where, (h)->temp.tempint),			      \
+   (h)->next_free += (h)->temp.tempint,					      \
+   *((h)->next_free)++ = 0)
+
+# define obstack_1grow(h, datum)					      \
+  ((((h)->next_free + 1 > (h)->chunk_limit)				      \
+    ? (_obstack_newchunk ((h), 1), 0) : 0),				      \
+   obstack_1grow_fast (h, datum))
+
+# define obstack_ptr_grow(h, datum)					      \
+  ((((h)->next_free + sizeof (char *) > (h)->chunk_limit)		      \
+    ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),		      \
+   obstack_ptr_grow_fast (h, datum))
+
+# define obstack_int_grow(h, datum)					      \
+  ((((h)->next_free + sizeof (int) > (h)->chunk_limit)			      \
+    ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),			      \
+   obstack_int_grow_fast (h, datum))
+
+# define obstack_ptr_grow_fast(h, aptr)					      \
+  (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+# define obstack_int_grow_fast(h, aint)					      \
+  (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
+
+# define obstack_blank(h, length)					      \
+  ((h)->temp.tempint = (length),					      \
+   (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint)		      \
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),		      \
+   obstack_blank_fast (h, (h)->temp.tempint))
+
+# define obstack_alloc(h, length)					      \
+  (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+# define obstack_copy(h, where, length)					      \
+  (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_copy0(h, where, length)				      \
+  (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_finish(h)						      \
+  (((h)->next_free == (h)->object_base					      \
+    ? (((h)->maybe_empty_object = 1), 0)				      \
+    : 0),								      \
+   (h)->temp.tempptr = (h)->object_base,				      \
+   (h)->next_free							      \
+     = __PTR_ALIGN ((h)->object_base, (h)->next_free,			      \
+		    (h)->alignment_mask),				      \
+   (((h)->next_free - (char *) (h)->chunk				      \
+     > (h)->chunk_limit - (char *) (h)->chunk)				      \
+   ? ((h)->next_free = (h)->chunk_limit) : 0),				      \
+   (h)->object_base = (h)->next_free,					      \
+   (h)->temp.tempptr)
+
+# define obstack_free(h, obj)						      \
+  ((h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,		      \
+   ((((h)->temp.tempint > 0						      \
+      && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk))	      \
+    ? (void) ((h)->next_free = (h)->object_base				      \
+	      = (h)->temp.tempint + (char *) (h)->chunk)		      \
+    : (__obstack_free) (h, (h)->temp.tempint + (char *) (h)->chunk)))
+
+#endif /* not __GNUC__ */
+
+#ifdef __cplusplus
+}       /* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow.c b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow.c
new file mode 100644
index 0000000..4714754
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow.c
@@ -0,0 +1,52 @@
+/* Variable-sized buffer with on-stack default allocation.
+   Copyright (C) 2015-2016 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 <scratch_buffer.h>
+#include <errno.h>
+
+bool
+__libc_scratch_buffer_grow (struct scratch_buffer *buffer)
+{
+  void *new_ptr;
+  size_t new_length = buffer->length * 2;
+
+  /* Discard old buffer.  */
+  scratch_buffer_free (buffer);
+
+  /* Check for overflow.  */
+  if (__glibc_likely (new_length >= buffer->length))
+    new_ptr = malloc (new_length);
+  else
+    {
+      __set_errno (ENOMEM);
+      new_ptr = NULL;
+    }
+
+  if (__glibc_unlikely (new_ptr == NULL))
+    {
+      /* Buffer must remain valid to free.  */
+      scratch_buffer_init (buffer);
+      return false;
+    }
+
+  /* Install new heap-based buffer.  */
+  buffer->data = new_ptr;
+  buffer->length = new_length;
+  return true;
+}
+libc_hidden_def (__libc_scratch_buffer_grow);
diff --git a/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow_preserve.c b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow_preserve.c
new file mode 100644
index 0000000..6aae41e
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_grow_preserve.c
@@ -0,0 +1,63 @@
+/* Variable-sized buffer with on-stack default allocation.
+   Copyright (C) 2015-2016 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 <scratch_buffer.h>
+#include <errno.h>
+#include <string.h>
+
+bool
+__libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
+{
+  size_t new_length = 2 * buffer->length;
+  void *new_ptr;
+
+  if (buffer->data == buffer->__space)
+    {
+      /* Move buffer to the heap.  No overflow is possible because
+	 buffer->length describes a small buffer on the stack.  */
+      new_ptr = malloc (new_length);
+      if (new_ptr == NULL)
+	return false;
+      memcpy (new_ptr, buffer->__space, buffer->length);
+    }
+  else
+    {
+      /* Buffer was already on the heap.  Check for overflow.  */
+      if (__glibc_likely (new_length >= buffer->length))
+	new_ptr = realloc (buffer->data, new_length);
+      else
+	{
+	  __set_errno (ENOMEM);
+	  new_ptr = NULL;
+	}
+
+      if (__glibc_unlikely (new_ptr == NULL))
+	{
+	  /* Deallocate, but buffer must remain valid to free.  */
+	  free (buffer->data);
+	  scratch_buffer_init (buffer);
+	  return false;
+	}
+    }
+
+  /* Install new heap-based buffer.  */
+  buffer->data = new_ptr;
+  buffer->length = new_length;
+  return true;
+}
+libc_hidden_def (__libc_scratch_buffer_grow_preserve);
diff --git a/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_set_array_size.c b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_set_array_size.c
new file mode 100644
index 0000000..3d33731
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/scratch_buffer_set_array_size.c
@@ -0,0 +1,59 @@
+/* Variable-sized buffer with on-stack default allocation.
+   Copyright (C) 2015-2016 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 <scratch_buffer.h>
+#include <errno.h>
+
+bool
+__libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
+				      size_t nelem, size_t size)
+{
+  size_t new_length = nelem * size;
+
+  /* Avoid overflow check if both values are small. */
+  if ((nelem | size) >> (sizeof (size_t) * CHAR_BIT / 2) != 0
+      && nelem != 0 && size != new_length / nelem)
+    {
+      /* Overflow.  Discard the old buffer, but it must remain valid
+	 to free.  */
+      scratch_buffer_free (buffer);
+      scratch_buffer_init (buffer);
+      __set_errno (ENOMEM);
+      return false;
+    }
+
+  if (new_length <= buffer->length)
+    return true;
+
+  /* Discard old buffer.  */
+  scratch_buffer_free (buffer);
+
+  char *new_ptr = malloc (new_length);
+  if (new_ptr == NULL)
+    {
+      /* Buffer must remain valid to free.  */
+      scratch_buffer_init (buffer);
+      return false;
+    }
+
+  /* Install new heap-based buffer.  */
+  buffer->data = new_ptr;
+  buffer->length = new_length;
+  return true;
+}
+libc_hidden_def (__libc_scratch_buffer_set_array_size);
diff --git a/ap/libc/glibc/glibc-2.23/malloc/set-freeres.c b/ap/libc/glibc/glibc-2.23/malloc/set-freeres.c
new file mode 100644
index 0000000..f614fd7
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/set-freeres.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1997-2016 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 <atomic.h>
+#include <stdlib.h>
+#include <set-hooks.h>
+#include <libc-internal.h>
+
+#include "../libio/libioP.h"
+
+DEFINE_HOOK (__libc_subfreeres, (void));
+
+symbol_set_define (__libc_freeres_ptrs);
+
+void __libc_freeres_fn_section
+__libc_freeres (void)
+{
+  /* This function might be called from different places.  So better
+     protect for multiple executions since these are fatal.  */
+  static long int already_called;
+
+  if (!atomic_compare_and_exchange_bool_acq (&already_called, 1, 0))
+    {
+      void *const *p;
+
+      _IO_cleanup ();
+
+      RUN_HOOK (__libc_subfreeres, ());
+
+      for (p = symbol_set_first_element (__libc_freeres_ptrs);
+           !symbol_set_end_p (__libc_freeres_ptrs, p); ++p)
+        free (*p);
+    }
+}
+libc_hidden_def (__libc_freeres)
diff --git a/ap/libc/glibc/glibc-2.23/malloc/thread-freeres.c b/ap/libc/glibc/glibc-2.23/malloc/thread-freeres.c
new file mode 100644
index 0000000..a8b5305
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/thread-freeres.c
@@ -0,0 +1,31 @@
+/* Free resources stored in thread-local variables on thread exit.
+   Copyright (C) 2003-2016 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 <libc-internal.h>
+#include <set-hooks.h>
+
+#ifdef _LIBC_REENTRANT
+DEFINE_HOOK (__libc_thread_subfreeres, (void));
+
+void __attribute__ ((section ("__libc_thread_freeres_fn")))
+__libc_thread_freeres (void)
+{
+  RUN_HOOK (__libc_thread_subfreeres, ());
+}
+#endif
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-calloc.c b/ap/libc/glibc/glibc-2.23/malloc/tst-calloc.c
new file mode 100644
index 0000000..9a879f4
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-calloc.c
@@ -0,0 +1,128 @@
+/* Copyright (C) 2000-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@redhat.com>.
+
+   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 <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/* Number of samples per size.  */
+#define N 50000
+
+
+static void
+fixed_test (int size)
+{
+  char *ptrs[N];
+  int i;
+
+  for (i = 0; i < N; ++i)
+    {
+      int j;
+
+      ptrs[i] = (char *) calloc (1, size);
+
+      if (ptrs[i] == NULL)
+	break;
+
+      for (j = 0; j < size; ++j)
+	{
+	  if (ptrs[i][j] != '\0')
+	    error (EXIT_FAILURE, 0,
+		   "byte not cleared (size %d, element %d, byte %d)",
+		   size, i, j);
+	  ptrs[i][j] = '\xff';
+	}
+    }
+
+  while (i-- > 0)
+    free (ptrs[i]);
+}
+
+
+static void
+random_test (void)
+{
+  char *ptrs[N];
+  int i;
+
+  for (i = 0; i < N; ++i)
+    {
+      int j;
+      int n = 1 + random () % 10;
+      int elem = 1 + random () % 100;
+      int size = n * elem;
+
+      ptrs[i] = (char *) calloc (n, elem);
+
+      if (ptrs[i] == NULL)
+	break;
+
+      for (j = 0; j < size; ++j)
+	{
+	  if (ptrs[i][j] != '\0')
+	    error (EXIT_FAILURE, 0,
+		   "byte not cleared (size %d, element %d, byte %d)",
+		   size, i, j);
+	  ptrs[i][j] = '\xff';
+	}
+    }
+
+  while (i-- > 0)
+    free (ptrs[i]);
+}
+
+
+static void
+null_test (void)
+{
+  /* If the size is 0 the result is implementation defined.  Just make
+     sure the program doesn't crash.  */
+  calloc (0, 0);
+  calloc (0, UINT_MAX);
+  calloc (UINT_MAX, 0);
+  calloc (0, ~((size_t) 0));
+  calloc (~((size_t) 0), 0);
+}
+
+
+static int
+do_test (void)
+{
+  /* We are allocating blocks with `calloc' and check whether every
+     block is completely cleared.  We first try this for some fixed
+     times and then with random size.  */
+  fixed_test (15);
+  fixed_test (5);
+  fixed_test (17);
+  fixed_test (6);
+  fixed_test (31);
+  fixed_test (96);
+
+  random_test ();
+
+  null_test ();
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-backtrace.c b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-backtrace.c
new file mode 100644
index 0000000..3aee7fd
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-backtrace.c
@@ -0,0 +1,55 @@
+/* Verify that backtrace does not deadlock on itself on memory corruption.
+   Copyright (C) 2015-2016 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>
+
+#define SIZE 4096
+
+/* Wrap free with a function to prevent gcc from optimizing it out.  */
+static void
+__attribute__((noinline))
+call_free (void *ptr)
+{
+  free (ptr);
+  *(size_t *)(ptr - sizeof (size_t)) = 1;
+}
+
+int do_test (void);
+
+#define TEST_FUNCTION do_test ()
+#define EXPECTED_SIGNAL SIGABRT
+
+#include "../test-skeleton.c"
+
+int
+do_test (void)
+{
+  void *ptr1 = malloc (SIZE);
+  void *ptr2 = malloc (SIZE);
+
+  /* Avoid unwanted output to TTY after an expected memory corruption.  */
+  ignore_stderr();
+
+  call_free (ptr1);
+  ptr1 = malloc (SIZE);
+
+  /* Not reached.  The return statement is to put ptr2 into use so that gcc
+     doesn't optimize out that malloc call.  */
+  return (ptr1 == ptr2);
+}
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-exit.c b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-exit.c
new file mode 100644
index 0000000..f4aa21a
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-exit.c
@@ -0,0 +1,217 @@
+/* Test malloc with concurrent thread termination.
+   Copyright (C) 2015-2016 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/>.  */
+
+/* This thread spawns a number of outer threads, equal to the arena
+   limit.  The outer threads run a loop which start and join two
+   different kinds of threads: the first kind allocates (attaching an
+   arena to the thread; malloc_first_thread) and waits, the second
+   kind waits and allocates (wait_first_threads).  Both kinds of
+   threads exit immediately after waiting.  The hope is that this will
+   exhibit races in thread termination and arena management,
+   particularly related to the arena free list.  */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define TIMEOUT 7
+
+static bool termination_requested;
+static int inner_thread_count = 4;
+static size_t malloc_size = 32;
+
+static void
+__attribute__ ((noinline, noclone))
+unoptimized_free (void *ptr)
+{
+  free (ptr);
+}
+
+static void *
+malloc_first_thread (void * closure)
+{
+  pthread_barrier_t *barrier = closure;
+  void *ptr = malloc (malloc_size);
+  if (ptr == NULL)
+    {
+      printf ("error: malloc: %m\n");
+      abort ();
+    }
+  int ret = pthread_barrier_wait (barrier);
+  if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      errno = ret;
+      printf ("error: pthread_barrier_wait: %m\n");
+      abort ();
+    }
+  unoptimized_free (ptr);
+  return NULL;
+}
+
+static void *
+wait_first_thread (void * closure)
+{
+  pthread_barrier_t *barrier = closure;
+  int ret = pthread_barrier_wait (barrier);
+  if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      errno = ret;
+      printf ("error: pthread_barrier_wait: %m\n");
+      abort ();
+    }
+  void *ptr = malloc (malloc_size);
+  if (ptr == NULL)
+    {
+      printf ("error: malloc: %m\n");
+      abort ();
+    }
+  unoptimized_free (ptr);
+  return NULL;
+}
+
+static void *
+outer_thread (void *closure)
+{
+  pthread_t *threads = calloc (sizeof (*threads), inner_thread_count);
+  if (threads == NULL)
+    {
+      printf ("error: calloc: %m\n");
+      abort ();
+    }
+
+  while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED))
+    {
+      pthread_barrier_t barrier;
+      int ret = pthread_barrier_init (&barrier, NULL, inner_thread_count + 1);
+      if (ret != 0)
+        {
+          errno = ret;
+          printf ("pthread_barrier_init: %m\n");
+          abort ();
+        }
+      for (int i = 0; i < inner_thread_count; ++i)
+        {
+          void *(*func) (void *);
+          if ((i  % 2) == 0)
+            func = malloc_first_thread;
+          else
+            func = wait_first_thread;
+          ret = pthread_create (threads + i, NULL, func, &barrier);
+          if (ret != 0)
+            {
+              errno = ret;
+              printf ("error: pthread_create: %m\n");
+              abort ();
+            }
+        }
+      ret = pthread_barrier_wait (&barrier);
+      if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+        {
+          errno = ret;
+          printf ("pthread_wait: %m\n");
+          abort ();
+        }
+      for (int i = 0; i < inner_thread_count; ++i)
+        {
+          ret = pthread_join (threads[i], NULL);
+          if (ret != 0)
+            {
+              ret = errno;
+              printf ("error: pthread_join: %m\n");
+              abort ();
+            }
+        }
+      ret = pthread_barrier_destroy (&barrier);
+      if (ret != 0)
+        {
+          ret = errno;
+          printf ("pthread_barrier_destroy: %m\n");
+          abort ();
+        }
+    }
+
+  free (threads);
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  /* The number of top-level threads should be equal to the number of
+     arenas.  See arena_get2.  */
+  long outer_thread_count = sysconf (_SC_NPROCESSORS_ONLN);
+  if (outer_thread_count >= 1)
+    {
+      /* See NARENAS_FROM_NCORES in malloc.c.  */
+      if (sizeof (long) == 4)
+        outer_thread_count *= 2;
+      else
+        outer_thread_count *= 8;
+    }
+
+  /* Leave some room for shutting down all threads gracefully.  */
+  int timeout = TIMEOUT - 2;
+
+  pthread_t *threads = calloc (sizeof (*threads), outer_thread_count);
+  if (threads == NULL)
+    {
+      printf ("error: calloc: %m\n");
+      abort ();
+    }
+
+  for (long i = 0; i < outer_thread_count; ++i)
+    {
+      int ret = pthread_create (threads + i, NULL, outer_thread, NULL);
+      if (ret != 0)
+        {
+          errno = ret;
+          printf ("error: pthread_create: %m\n");
+          abort ();
+        }
+    }
+
+  struct timespec ts = {timeout, 0};
+  if (nanosleep (&ts, NULL))
+    {
+      printf ("error: error: nanosleep: %m\n");
+      abort ();
+    }
+
+  __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED);
+
+  for (long i = 0; i < outer_thread_count; ++i)
+    {
+      int ret = pthread_join (threads[i], NULL);
+      if (ret != 0)
+        {
+          errno = ret;
+          printf ("error: pthread_join: %m\n");
+          abort ();
+        }
+    }
+  free (threads);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-fail.c b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-fail.c
new file mode 100644
index 0000000..fc090ef
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-thread-fail.c
@@ -0,0 +1,442 @@
+/* Test allocation function behavior on allocation failure.
+   Copyright (C) 2015-2016 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; see the file COPYING.LIB.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+/* This test case attempts to trigger various unusual conditions
+   related to allocation failures, notably switching to a different
+   arena, and falling back to mmap (via sysmalloc).  */
+
+#include <errno.h>
+#include <malloc.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+/* Wrapper for calloc with an optimization barrier.  */
+static void *
+__attribute__ ((noinline, noclone))
+allocate_zeroed (size_t a, size_t b)
+{
+  return calloc (a, b);
+}
+
+/* System page size, as determined by sysconf (_SC_PAGE_SIZE).  */
+static unsigned long page_size;
+
+/* Test parameters. */
+static size_t allocation_size;
+static size_t alignment;
+static enum {
+  with_malloc,
+  with_realloc,
+  with_aligned_alloc,
+  with_memalign,
+  with_posix_memalign,
+  with_valloc,
+  with_pvalloc,
+  with_calloc,
+  last_allocation_function = with_calloc
+} allocation_function;
+
+/* True if an allocation function uses the alignment test
+   parameter.  */
+const static bool alignment_sensitive[last_allocation_function + 1] =
+  {
+    [with_aligned_alloc] = true,
+    [with_memalign] = true,
+    [with_posix_memalign] = true,
+  };
+
+/* Combined pointer/expected alignment result of an allocation
+   function.  */
+struct allocate_result {
+  void *pointer;
+  size_t alignment;
+};
+
+/* Call the allocation function specified by allocation_function, with
+   allocation_size and alignment (if applicable) as arguments.  No
+   alignment check.  */
+static struct allocate_result
+allocate_1 (void)
+{
+  switch (allocation_function)
+    {
+    case with_malloc:
+      return (struct allocate_result)
+        {malloc (allocation_size), _Alignof (max_align_t)};
+    case with_realloc:
+      {
+        void *p = realloc (NULL, 16);
+        void *q;
+        if (p == NULL)
+          q = NULL;
+        else
+          {
+            q = realloc (p, allocation_size);
+            if (q == NULL)
+              free (p);
+          }
+        return (struct allocate_result) {q, _Alignof (max_align_t)};
+      }
+    case with_aligned_alloc:
+      {
+        void *p = aligned_alloc (alignment, allocation_size);
+        return (struct allocate_result) {p, alignment};
+      }
+    case with_memalign:
+      {
+        void *p = memalign (alignment, allocation_size);
+        return (struct allocate_result) {p, alignment};
+      }
+    case with_posix_memalign:
+      {
+        void *p;
+        if (posix_memalign (&p, alignment, allocation_size))
+          {
+            if (errno == ENOMEM)
+              p = NULL;
+            else
+              {
+                printf ("error: posix_memalign (p, %zu, %zu): %m\n",
+                        alignment, allocation_size);
+                abort ();
+              }
+          }
+        return (struct allocate_result) {p, alignment};
+      }
+    case with_valloc:
+      {
+        void *p = valloc (allocation_size);
+        return (struct allocate_result) {p, page_size};
+      }
+    case with_pvalloc:
+      {
+        void *p = pvalloc (allocation_size);
+        return (struct allocate_result) {p, page_size};
+      }
+    case with_calloc:
+      {
+        char *p = allocate_zeroed (1, allocation_size);
+        /* Check for non-zero bytes.  */
+        if (p != NULL)
+          for (size_t i = 0; i < allocation_size; ++i)
+            if (p[i] != 0)
+              {
+                printf ("error: non-zero byte at offset %zu\n", i);
+                abort ();
+              }
+        return (struct allocate_result) {p, _Alignof (max_align_t)};
+      }
+    }
+  abort ();
+}
+
+/* Call allocate_1 and perform the alignment check on the result.  */
+static void *
+allocate (void)
+{
+  struct allocate_result r = allocate_1 ();
+  if ((((uintptr_t) r.pointer) & (r.alignment - 1)) != 0)
+    {
+      printf ("error: allocation function %d, size %zu not aligned to %zu\n",
+              (int) allocation_function, allocation_size, r.alignment);
+      abort ();
+    }
+  return r.pointer;
+}
+
+/* Barriers to synchronize thread creation and termination.  */
+static pthread_barrier_t start_barrier;
+static pthread_barrier_t end_barrier;
+
+/* Thread function which performs the allocation test.  Called by
+   pthread_create and from the main thread.  */
+static void *
+allocate_thread (void *closure)
+{
+  /* Wait for the creation of all threads.  */
+  {
+    int ret = pthread_barrier_wait (&start_barrier);
+    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_wait: %m\n");
+        abort ();
+      }
+  }
+
+  /* Allocate until we run out of memory, creating a single-linked
+     list.  */
+  struct list {
+    struct list *next;
+  };
+  struct list *head = NULL;
+  while (true)
+    {
+      struct list *e = allocate ();
+      if (e == NULL)
+        break;
+
+      e->next = head;
+      head = e;
+    }
+
+  /* Wait for the allocation of all available memory.  */
+  {
+    int ret = pthread_barrier_wait (&end_barrier);
+    if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_wait: %m\n");
+        abort ();
+      }
+  }
+
+  /* Free the allocated memory.  */
+  while (head != NULL)
+    {
+      struct list *next = head->next;
+      free (head);
+      head = next;
+    }
+
+  return NULL;
+}
+
+/* Number of threads (plus the main thread.  */
+enum { thread_count = 8 };
+
+/* Thread attribute to request creation of threads with a non-default
+   stack size which is rather small.  This avoids interfering with the
+   configured address space limit.  */
+static pthread_attr_t small_stack;
+
+/* Runs one test in multiple threads, all in a subprocess so that
+   subsequent tests do not interfere with each other.  */
+static void
+run_one (void)
+{
+  /* Isolate the tests in a subprocess, so that we can start over
+     from scratch.  */
+  pid_t pid = fork ();
+  if (pid == 0)
+    {
+      /* In the child process.  Create the allocation threads.  */
+      pthread_t threads[thread_count];
+
+      for (unsigned i = 0; i < thread_count; ++i)
+        {
+          int ret = pthread_create (threads + i, &small_stack, allocate_thread, NULL);
+          if (ret != 0)
+            {
+              errno = ret;
+              printf ("error: pthread_create: %m\n");
+              abort ();
+            }
+        }
+
+      /* Also run the test on the main thread.  */
+      allocate_thread (NULL);
+
+      for (unsigned i = 0; i < thread_count; ++i)
+        {
+          int ret = pthread_join (threads[i], NULL);
+          if (ret != 0)
+            {
+              errno = ret;
+              printf ("error: pthread_join: %m\n");
+              abort ();
+            }
+        }
+      _exit (0);
+    }
+  else if (pid < 0)
+    {
+      printf ("error: fork: %m\n");
+      abort ();
+    }
+
+  /* In the parent process.  Wait for the child process to exit.  */
+  int status;
+  if (waitpid (pid, &status, 0) < 0)
+    {
+      printf ("error: waitpid: %m\n");
+      abort ();
+    }
+  if (status != 0)
+    {
+      printf ("error: exit status %d from child process\n", status);
+      exit (1);
+    }
+}
+
+/* Run all applicable allocation functions for the current test
+   parameters.  */
+static void
+run_allocation_functions (void)
+{
+  for (int af = 0; af <= last_allocation_function; ++af)
+    {
+      /* Run alignment-sensitive functions for non-default
+         alignments.  */
+      if (alignment_sensitive[af] != (alignment != 0))
+        continue;
+      allocation_function = af;
+      run_one ();
+    }
+}
+
+int
+do_test (void)
+{
+  /* Limit the number of malloc arenas.  We use a very low number so
+     that despute the address space limit configured below, all
+     requested arenas a can be created.  */
+  if (mallopt (M_ARENA_MAX, 2) == 0)
+    {
+      printf ("error: mallopt (M_ARENA_MAX) failed\n");
+      return 1;
+    }
+
+  /* Determine the page size.  */
+  {
+    long ret = sysconf (_SC_PAGE_SIZE);
+    if (ret < 0)
+      {
+        printf ("error: sysconf (_SC_PAGE_SIZE): %m\n");
+        return 1;
+      }
+    page_size = ret;
+  }
+
+  /* Limit the size of the process, so that memory allocation in
+     allocate_thread will eventually fail, without impacting the
+     entire system.  */
+  {
+    struct rlimit limit;
+    if (getrlimit (RLIMIT_AS, &limit) != 0)
+      {
+        printf ("getrlimit (RLIMIT_AS) failed: %m\n");
+        return 1;
+      }
+    long target = 200 * 1024 * 1024;
+    if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
+      {
+        limit.rlim_cur = target;
+        if (setrlimit (RLIMIT_AS, &limit) != 0)
+          {
+            printf ("setrlimit (RLIMIT_AS) failed: %m\n");
+            return 1;
+          }
+      }
+  }
+
+  /* Initialize thread attribute with a reduced stack size.  */
+  {
+    int ret = pthread_attr_init (&small_stack);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_attr_init: %m\n");
+        abort ();
+      }
+    unsigned long stack_size = ((256 * 1024) / page_size) * page_size;
+    if (stack_size < 4 * page_size)
+      stack_size = 8 * page_size;
+    ret = pthread_attr_setstacksize (&small_stack, stack_size);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_attr_setstacksize: %m\n");
+        abort ();
+      }
+  }
+
+  /* Initialize the barriers.  We run thread_count threads, plus 1 for
+     the main thread.  */
+  {
+    int ret = pthread_barrier_init (&start_barrier, NULL, thread_count + 1);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_init: %m\n");
+        abort ();
+      }
+
+    ret = pthread_barrier_init (&end_barrier, NULL, thread_count + 1);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_init: %m\n");
+        abort ();
+      }
+  }
+
+  allocation_size = 144;
+  run_allocation_functions ();
+  allocation_size = page_size;
+  run_allocation_functions ();
+
+  alignment = 128;
+  allocation_size = 512;
+  run_allocation_functions ();
+
+  allocation_size = page_size;
+  run_allocation_functions ();
+
+  allocation_size = 17 * page_size;
+  run_allocation_functions ();
+
+  /* Deallocation the barriers and the thread attribute.  */
+  {
+    int ret = pthread_barrier_destroy (&end_barrier);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_destroy: %m\n");
+        return 1;
+      }
+    ret = pthread_barrier_destroy (&start_barrier);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_barrier_destroy: %m\n");
+        return 1;
+      }
+    ret = pthread_attr_destroy (&small_stack);
+    if (ret != 0)
+      {
+        errno = ret;
+        printf ("error: pthread_attr_destroy: %m\n");
+        return 1;
+      }
+  }
+
+  return 0;
+}
+
+/* The repeated allocations take some time on slow machines.  */
+#define TIMEOUT 20
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-usable.c b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-usable.c
new file mode 100644
index 0000000..ca67ed7
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc-usable.c
@@ -0,0 +1,49 @@
+/* Ensure that malloc_usable_size returns the request size with
+   MALLOC_CHECK_ exported to a positive value.
+
+   Copyright (C) 2012-2016 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 <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+static int
+do_test (void)
+{
+  size_t usable_size;
+  void *p = malloc (7);
+  if (!p)
+    {
+      printf ("memory allocation failed\n");
+      return 1;
+    }
+
+  usable_size = malloc_usable_size (p);
+  if (usable_size != 7)
+    {
+      printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size);
+      return 1;
+    }
+
+  memset (p, 0, usable_size);
+  free (p);
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-malloc.c b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc.c
new file mode 100644
index 0000000..c1292a2
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-malloc.c
@@ -0,0 +1,80 @@
+/* Copyright (C) 1999-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Andreas Jaeger <aj@arthur.rhein-neckar.de>, 1999.
+
+   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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p, *q;
+  int save;
+
+  errno = 0;
+
+  p = malloc (-1);
+  save = errno;
+
+  if (p != NULL)
+    merror ("malloc (-1) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("errno is not set correctly");
+
+  p = malloc (10);
+  if (p == NULL)
+    merror ("malloc (10) failed.");
+
+  /* realloc (p, 0) == free (p).  */
+  p = realloc (p, 0);
+  if (p != NULL)
+    merror ("realloc (p, 0) failed.");
+
+  p = malloc (0);
+  if (p == NULL)
+    merror ("malloc (0) failed.");
+
+  p = realloc (p, 0);
+  if (p != NULL)
+    merror ("realloc (p, 0) failed.");
+
+  p = malloc (513 * 1024);
+  if (p == NULL)
+    merror ("malloc (513K) failed.");
+
+  q = malloc (-512 * 1024);
+  if (q != NULL)
+    merror ("malloc (-512K) succeeded.");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mallocfork.c b/ap/libc/glibc/glibc-2.23/malloc/tst-mallocfork.c
new file mode 100644
index 0000000..f90ce94
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mallocfork.c
@@ -0,0 +1,51 @@
+/* Derived from the test case in
+   http://sourceware.org/bugzilla/show_bug.cgi?id=838.  */
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static void
+sig_handler (int signum)
+{
+  pid_t child = fork ();
+  if (child == 0)
+    exit (0);
+  TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
+}
+
+static int
+do_test (void)
+{
+  pid_t parent = getpid ();
+
+  struct sigaction action = { .sa_handler = sig_handler };
+  sigemptyset (&action.sa_mask);
+
+  malloc (sizeof (int));
+
+  if (sigaction (SIGALRM, &action, NULL) != 0)
+    {
+      puts ("sigaction failed");
+      return 1;
+    }
+
+  /* Create a child that sends the signal to be caught.  */
+  pid_t child = fork ();
+  if (child == 0)
+    {
+      if (kill (parent, SIGALRM) == -1)
+	perror ("kill");
+      exit (0);
+    }
+
+  TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mallocstate.c b/ap/libc/glibc/glibc-2.23/malloc/tst-mallocstate.c
new file mode 100644
index 0000000..a00d045
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mallocstate.c
@@ -0,0 +1,84 @@
+/* Copyright (C) 2001-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
+
+   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 <errno.h>
+#include <stdio.h>
+#include "malloc.h"
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p1, *p2;
+  void *save_state;
+  long i;
+
+  errno = 0;
+
+  p1 = malloc (10);
+  if (p1 == NULL)
+    merror ("malloc (10) failed.");
+
+  p2 = malloc (20);
+  if (p2 == NULL)
+    merror ("malloc (20) failed.");
+
+  free (malloc (10));
+
+  for (i = 0; i < 100; ++i)
+    {
+      save_state = malloc_get_state ();
+      if (save_state == NULL)
+        {
+          merror ("malloc_get_state () failed.");
+          break;
+        }
+      /*free (malloc (10)); This could change the top chunk! */
+      malloc_set_state (save_state);
+      p1 = realloc (p1, i * 4 + 4);
+      if (p1 == NULL)
+        merror ("realloc (i*4) failed.");
+      free (save_state);
+    }
+
+  p1 = realloc (p1, 40);
+  free (p2);
+  p2 = malloc (10);
+  if (p2 == NULL)
+    merror ("malloc (10) failed.");
+  free (p1);
+
+  return errors != 0;
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 2
+ * End:
+ */
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mallopt.c b/ap/libc/glibc/glibc-2.23/malloc/tst-mallopt.c
new file mode 100644
index 0000000..390fba3
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mallopt.c
@@ -0,0 +1,75 @@
+/* Copyright (C) 2014-2016 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 <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  int ret;
+
+  ret = mallopt(M_CHECK_ACTION, 1);
+
+  if (ret != 1)
+    merror ("mallopt (M_CHECK_ACTION, 1) failed.");
+
+  ret = mallopt(M_MMAP_MAX, 64*1024);
+
+  if (ret != 1)
+    merror ("mallopt (M_MMAP_MAX, 64*1024) failed.");
+
+  ret = mallopt(M_MMAP_THRESHOLD, 64*1024);
+
+  if (ret != 1)
+    merror ("mallopt (M_MMAP_THRESHOLD, 64*1024) failed.");
+
+  ret = mallopt(M_MXFAST, 0);
+
+  if (ret != 1)
+    merror ("mallopt (M_MXFAST, 0) failed.");
+
+  ret = mallopt(M_PERTURB, 0xa5);
+
+  if (ret != 1)
+    merror ("mallopt (M_PERTURB, 0xa5) failed.");
+
+  ret = mallopt(M_TOP_PAD, 64*1024);
+
+  if (ret != 1)
+    merror ("mallopt (M_TOP_PAD, 64*1024) failed.");
+
+  ret = mallopt(M_TRIM_THRESHOLD, -1);
+
+  if (ret != 1)
+    merror ("mallopt (M_TRIM_THRESHOLD, -1) failed.");
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mcheck.c b/ap/libc/glibc/glibc-2.23/malloc/tst-mcheck.c
new file mode 100644
index 0000000..296cc47
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mcheck.c
@@ -0,0 +1,93 @@
+/* Copyright (C) 2005-2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2005.
+
+   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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p, *q;
+
+  errno = 0;
+
+  p = malloc (-1);
+
+  if (p != NULL)
+    merror ("malloc (-1) succeeded.");
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly.");
+
+  p = malloc (10);
+  if (p == NULL)
+    merror ("malloc (10) failed.");
+
+  p = realloc (p, 0);
+  if (p != NULL)
+    merror ("realloc (p, 0) failed.");
+
+  p = malloc (0);
+  if (p == NULL)
+    merror ("malloc (0) failed.");
+
+  p = realloc (p, 0);
+  if (p != NULL)
+    merror ("realloc (p, 0) failed.");
+
+  q = malloc (256);
+  if (q == NULL)
+    merror ("malloc (256) failed.");
+
+  p = malloc (512);
+  if (p == NULL)
+    merror ("malloc (512) failed.");
+
+  if (realloc (p, -256) != NULL)
+    merror ("realloc (p, -256) succeeded.");
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly.");
+
+  free (p);
+
+  p = malloc (512);
+  if (p == NULL)
+    merror ("malloc (512) failed.");
+
+  if (realloc (p, -1) != NULL)
+    merror ("realloc (p, -1) succeeded.");
+  else if (errno != ENOMEM)
+    merror ("errno is not set correctly.");
+
+  free (p);
+  free (q);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-memalign.c b/ap/libc/glibc/glibc-2.23/malloc/tst-memalign.c
new file mode 100644
index 0000000..6650610
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-memalign.c
@@ -0,0 +1,114 @@
+/* Test for memalign.
+   Copyright (C) 2013-2016 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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p;
+  unsigned long pagesize = getpagesize ();
+  unsigned long ptrval;
+  int save;
+
+  errno = 0;
+
+  /* An attempt to allocate a huge value should return NULL and set
+     errno to ENOMEM.  */
+  p = memalign (sizeof (void *), -1);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("memalign (sizeof (void *), -1) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("memalign (sizeof (void *), -1) errno is not set correctly");
+
+  free (p);
+
+  errno = 0;
+
+  /* Test to expose integer overflow in malloc internals from BZ #15857.  */
+  p = memalign (pagesize, -pagesize);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("memalign (pagesize, -pagesize) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("memalign (pagesize, -pagesize) errno is not set correctly");
+
+  free (p);
+
+  errno = 0;
+
+  /* Test to expose integer overflow in malloc internals from BZ #16038.  */
+  p = memalign (-1, pagesize);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("memalign (-1, pagesize) succeeded.");
+
+  if (p == NULL && save != EINVAL)
+    merror ("memalign (-1, pagesize) errno is not set correctly");
+
+  free (p);
+
+  /* A zero-sized allocation should succeed with glibc, returning a
+     non-NULL value.  */
+  p = memalign (sizeof (void *), 0);
+
+  if (p == NULL)
+    merror ("memalign (sizeof (void *), 0) failed.");
+
+  free (p);
+
+  /* Check the alignment of the returned pointer is correct.  */
+  p = memalign (0x100, 10);
+
+  if (p == NULL)
+    merror ("memalign (0x100, 10) failed.");
+
+  ptrval = (unsigned long) p;
+
+  if ((ptrval & 0xff) != 0)
+    merror ("pointer is not aligned to 0x100");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.c b/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.c
new file mode 100644
index 0000000..fc44226
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.c
@@ -0,0 +1,105 @@
+/* Test program for mtrace.
+   Copyright (C) 2000-2016 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 <mcheck.h>
+#include <paths.h>
+#include <search.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static void print (const void *node, VISIT value, int level);
+
+/* Used for several purposes.  */
+static FILE *fp;
+
+
+static int
+do_test (void)
+{
+  void *root = NULL;
+  size_t linelen = 0;
+  char *line = NULL;
+
+  /* Enable memory usage tracing.  */
+  mtrace ();
+
+  /* Perform some operations which definitely will allocate some
+     memory.  */
+  fp = fopen (__FILE__, "r");
+  if (fp == NULL)
+    /* Shouldn't happen since this program is executed in the source
+       directory.  */
+    abort ();
+
+  while (!feof (fp))
+    {
+      char **p;
+      char *copy;
+      ssize_t n = getline (&line, &linelen, fp);
+
+      if (n < 0)
+        break;
+
+      if (n == 0)
+        continue;
+
+      copy = strdup (line);
+      if (copy == NULL)
+        abort ();
+
+      p = (char **) tsearch (copy, &root,
+                             (int (*)(const void *, const void *))strcmp);
+      if (*p != copy)
+        /* This line wasn't added.  */
+        free (copy);
+    }
+
+  fclose (fp);
+
+  fp = fopen (_PATH_DEVNULL, "w");
+  if (fp != NULL)
+    {
+      /* Write something through stdout.  */
+      twalk (root, print);
+
+      fclose (fp);
+    }
+
+  /* Free everything.  */
+  tdestroy (root, free);
+
+  /* Also the line buffer.  */
+  free (line);
+
+  /* That's it.  */
+  return 0;
+}
+
+
+static void
+print (const void *node, VISIT value, int level)
+{
+  static int cnt;
+  if (value == postorder || value == leaf)
+    fprintf (fp, "%3d: %s", ++cnt, *(const char **) node);
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.sh b/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.sh
new file mode 100755
index 0000000..cbcaea8
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-mtrace.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Testing the mtrace function.
+# Copyright (C) 2000-2016 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/>.
+
+set -e
+
+common_objpfx=$1; shift
+test_program_prefix_before_env=$1; shift
+run_program_env=$1; shift
+test_program_prefix_after_env=$1; shift
+
+status=0
+trap "rm -f ${common_objpfx}malloc/tst-mtrace.leak; exit 1" 1 2 15
+
+${test_program_prefix_before_env} \
+${run_program_env} \
+MALLOC_TRACE=${common_objpfx}malloc/tst-mtrace.leak \
+${test_program_prefix_after_env} \
+  ${common_objpfx}malloc/tst-mtrace || status=1
+
+if test $status -eq 0 && test -f ${common_objpfx}malloc/mtrace; then
+  ${common_objpfx}malloc/mtrace ${common_objpfx}malloc/tst-mtrace.leak \
+    > ${common_objpfx}malloc/tst-mtrace.out|| status=1
+fi
+
+rm -f ${common_objpfx}malloc/tst-mtrace.leak
+
+exit $status
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-obstack.c b/ap/libc/glibc/glibc-2.23/malloc/tst-obstack.c
new file mode 100644
index 0000000..ee1385d
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-obstack.c
@@ -0,0 +1,67 @@
+/* Test case by Alexandre Duret-Lutz <duret_g@epita.fr>.  */
+#include <obstack.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define obstack_chunk_alloc verbose_malloc
+#define obstack_chunk_free verbose_free
+#define ALIGN_BOUNDARY 64
+#define ALIGN_MASK (ALIGN_BOUNDARY - 1)
+#define OBJECT_SIZE 1000
+
+static void *
+verbose_malloc (size_t size)
+{
+  void *buf = malloc (size);
+  printf ("malloc (%zu) => %p\n", size, buf);
+  return buf;
+}
+
+static void
+verbose_free (void *buf)
+{
+  free (buf);
+  printf ("free (%p)\n", buf);
+}
+
+static int
+do_test (void)
+{
+  int result = 0;
+  int align = 2;
+
+  while (align <= 64)
+    {
+      struct obstack obs;
+      int i;
+      int align_mask = align - 1;
+
+      printf ("\n Alignment mask: %d\n", align_mask);
+
+      obstack_init (&obs);
+      obstack_alignment_mask (&obs) = align_mask;
+      /* finish an empty object to take alignment into account */
+      obstack_finish (&obs);
+
+      /* let's allocate some objects and print their addresses */
+      for (i = 15; i > 0; --i)
+	{
+	  void *obj = obstack_alloc (&obs, OBJECT_SIZE);
+
+	  printf ("obstack_alloc (%u) => %p \t%s\n", OBJECT_SIZE, obj,
+		  ((uintptr_t) obj & align_mask) ? "(not aligned)" : "");
+	  result |= ((uintptr_t) obj & align_mask) != 0;
+	}
+
+      /* clean up */
+      obstack_free (&obs, 0);
+
+      align <<= 1;
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-posix_memalign.c b/ap/libc/glibc/glibc-2.23/malloc/tst-posix_memalign.c
new file mode 100644
index 0000000..0545599
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-posix_memalign.c
@@ -0,0 +1,118 @@
+/* Test for posix_memalign.
+   Copyright (C) 2013-2016 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 <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p;
+  int ret;
+  unsigned long pagesize = getpagesize ();
+  unsigned long ptrval;
+
+  p = NULL;
+
+  /* An attempt to allocate a huge value should return ENOMEM and
+     p should remain NULL.  */
+  ret = posix_memalign (&p, sizeof (void *), -1);
+
+  if (ret != ENOMEM)
+    merror ("posix_memalign (&p, sizeof (void *), -1) succeeded.");
+
+  if (ret == ENOMEM && p != NULL)
+    merror ("returned an error but pointer was modified");
+
+  free (p);
+
+  p = NULL;
+
+  /* Test to expose integer overflow in malloc internals from BZ #15857.  */
+  ret = posix_memalign (&p, pagesize, -pagesize);
+
+  if (ret != ENOMEM)
+    merror ("posix_memalign (&p, pagesize, -pagesize) succeeded.");
+
+  free (p);
+
+  p = NULL;
+
+  /* Test to expose integer overflow in malloc internals from BZ #16038.  */
+  ret = posix_memalign (&p, -1, pagesize);
+
+  if (ret != EINVAL)
+    merror ("posix_memalign (&p, -1, pagesize) succeeded.");
+
+  free (p);
+
+  p = NULL;
+
+  /* A zero-sized allocation should succeed with glibc, returning zero
+     and setting p to a non-NULL value.  */
+  ret = posix_memalign (&p, sizeof (void *), 0);
+
+  if (ret != 0 || p == NULL)
+    merror ("posix_memalign (&p, sizeof (void *), 0) failed.");
+
+  free (p);
+
+  ret = posix_memalign (&p, 0x300, 10);
+
+  if (ret != EINVAL)
+    merror ("posix_memalign (&p, 0x300, 10) succeeded.");
+
+  ret = posix_memalign (&p, 0, 10);
+
+  if (ret != EINVAL)
+    merror ("posix_memalign (&p, 0, 10) succeeded.");
+
+  p = NULL;
+
+  ret = posix_memalign (&p, 0x100, 10);
+
+  if (ret != 0)
+    merror ("posix_memalign (&p, 0x100, 10) failed.");
+
+  if (ret == 0 && p == NULL)
+    merror ("returned success but pointer is NULL");
+
+  ptrval = (unsigned long) p;
+
+  if (ret == 0 && (ptrval & 0xff) != 0)
+    merror ("pointer is not aligned to 0x100");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-pvalloc.c b/ap/libc/glibc/glibc-2.23/malloc/tst-pvalloc.c
new file mode 100644
index 0000000..ffce702
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-pvalloc.c
@@ -0,0 +1,99 @@
+/* Test for pvalloc.
+   Copyright (C) 2013-2016 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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p;
+  unsigned long pagesize = getpagesize ();
+  unsigned long ptrval;
+  int save;
+
+  errno = 0;
+
+  /* An attempt to allocate a huge value should return NULL and set
+     errno to ENOMEM.  */
+  p = pvalloc (-1);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("pvalloc (-1) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("pvalloc (-1) errno is not set correctly");
+
+  free (p);
+
+  errno = 0;
+
+  /* Test to expose integer overflow in malloc internals from BZ #15855.  */
+  p = pvalloc (-pagesize);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("pvalloc (-pagesize) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("pvalloc (-pagesize) errno is not set correctly");
+
+  free (p);
+
+  /* A zero-sized allocation should succeed with glibc, returning a
+     non-NULL value.  */
+  p = pvalloc (0);
+
+  if (p == NULL)
+    merror ("pvalloc (0) failed.");
+
+  free (p);
+
+  /* Check the alignment of the returned pointer is correct.  */
+  p = pvalloc (32);
+
+  if (p == NULL)
+    merror ("pvalloc (32) failed.");
+
+  ptrval = (unsigned long) p;
+
+  if ((ptrval & (pagesize - 1)) != 0)
+    merror ("returned pointer is not page aligned.");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-realloc.c b/ap/libc/glibc/glibc-2.23/malloc/tst-realloc.c
new file mode 100644
index 0000000..16e840f
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-realloc.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2013-2016 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 <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p;
+  unsigned char *c;
+  int save, i, ok;
+
+  errno = 0;
+
+  /* realloc (NULL, ...) behaves similarly to malloc (C89).  */
+  p = realloc (NULL, -1);
+  save = errno;
+
+  if (p != NULL)
+    merror ("realloc (NULL, -1) succeeded.");
+
+  /* errno should be set to ENOMEM on failure (POSIX).  */
+  if (p == NULL && save != ENOMEM)
+    merror ("errno is not set correctly");
+
+  errno = 0;
+
+  /* realloc (NULL, ...) behaves similarly to malloc (C89).  */
+  p = realloc (NULL, 10);
+  save = errno;
+
+  if (p == NULL)
+    merror ("realloc (NULL, 10) failed.");
+
+  /* errno should be clear on success (POSIX).  */
+  if (p != NULL && save != 0)
+    merror ("errno is set but should not be");
+
+  free (p);
+
+  p = calloc (20, 1);
+  if (p == NULL)
+    merror ("calloc (20, 1) failed.");
+
+  /* Check increasing size preserves contents (C89).  */
+  p = realloc (p, 200);
+  if (p == NULL)
+    merror ("realloc (p, 200) failed.");
+
+  c = p;
+  ok = 1;
+
+  for (i = 0; i < 20; i++)
+    {
+      if (c[i] != 0)
+        ok = 0;
+    }
+
+  if (ok == 0)
+    merror ("first 20 bytes were not cleared");
+
+  free (p);
+
+  p = realloc (NULL, 100);
+  if (p == NULL)
+    merror ("realloc (NULL, 100) failed.");
+
+  memset (p, 0xff, 100);
+
+  /* Check decreasing size preserves contents (C89).  */
+  p = realloc (p, 16);
+  if (p == NULL)
+    merror ("realloc (p, 16) failed.");
+
+  c = p;
+  ok = 1;
+
+  for (i = 0; i < 16; i++)
+    {
+      if (c[i] != 0xff)
+        ok = 0;
+    }
+
+  if (ok == 0)
+    merror ("first 16 bytes were not correct");
+
+  /* Check failed realloc leaves original untouched (C89).  */
+  c = realloc (p, -1);
+  if (c != NULL)
+    merror ("realloc (p, -1) succeeded.");
+
+  c = p;
+  ok = 1;
+
+  for (i = 0; i < 16; i++)
+    {
+      if (c[i] != 0xff)
+        ok = 0;
+    }
+
+  if (ok == 0)
+    merror ("first 16 bytes were not correct after failed realloc");
+
+  /* realloc (p, 0) frees p (C89) and returns NULL (glibc).  */
+  p = realloc (p, 0);
+  if (p != NULL)
+    merror ("realloc (p, 0) returned non-NULL.");
+
+  /* realloc (NULL, 0) acts like malloc (0) (glibc).  */
+  p = realloc (NULL, 0);
+  if (p == NULL)
+    merror ("realloc (NULL, 0) returned NULL.");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-scratch_buffer.c b/ap/libc/glibc/glibc-2.23/malloc/tst-scratch_buffer.c
new file mode 100644
index 0000000..073a6db
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-scratch_buffer.c
@@ -0,0 +1,155 @@
+/*
+   Copyright (C) 2015-2016 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 <scratch_buffer.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+static bool
+unchanged_array_size (struct scratch_buffer *buf, size_t a, size_t b)
+{
+  size_t old_length = buf->length;
+  if (!scratch_buffer_set_array_size (buf, a, b))
+    {
+      printf ("scratch_buffer_set_array_size failed: %zu %zu\n",
+	      a, b);
+      return false;
+    }
+  if (old_length != buf->length)
+    {
+      printf ("scratch_buffer_set_array_size did not preserve size: %zu %zu\n",
+	      a, b);
+      return false;
+    }
+  return true;
+}
+
+static bool
+array_size_must_fail (size_t a, size_t b)
+{
+  for (int pass = 0; pass < 2; ++pass)
+    {
+      struct scratch_buffer buf;
+      scratch_buffer_init (&buf);
+      if (pass > 0)
+	if (!scratch_buffer_grow (&buf))
+	  {
+	    printf ("scratch_buffer_grow in array_size_must_fail failed\n");
+	    return false;
+	  }
+      if (scratch_buffer_set_array_size (&buf, a, b))
+	{
+	  printf ("scratch_buffer_set_array_size passed: %d %zu %zu\n",
+		  pass, a, b);
+	  return false;
+	}
+      if (buf.data != buf.__space)
+	{
+	  printf ("scratch_buffer_set_array_size did not free: %d %zu %zu\n",
+		  pass, a, b);
+	  return false;
+	}
+    }
+  return true;
+}
+
+static int
+do_test (void)
+{
+  {
+    struct scratch_buffer buf;
+    scratch_buffer_init (&buf);
+    memset (buf.data, ' ', buf.length);
+    scratch_buffer_free (&buf);
+  }
+  {
+    struct scratch_buffer buf;
+    scratch_buffer_init (&buf);
+    memset (buf.data, ' ', buf.length);
+    size_t old_length = buf.length;
+    scratch_buffer_grow (&buf);
+    if (buf.length <= old_length)
+      {
+	printf ("scratch_buffer_grow did not enlarge buffer\n");
+	return 1;
+      }
+    memset (buf.data, ' ', buf.length);
+    scratch_buffer_free (&buf);
+  }
+  {
+    struct scratch_buffer buf;
+    scratch_buffer_init (&buf);
+    memset (buf.data, '@', buf.length);
+    strcpy (buf.data, "prefix");
+    size_t old_length = buf.length;
+    scratch_buffer_grow_preserve (&buf);
+    if (buf.length <= old_length)
+      {
+	printf ("scratch_buffer_grow_preserve did not enlarge buffer\n");
+	return 1;
+      }
+    if (strcmp (buf.data, "prefix") != 0)
+      {
+	printf ("scratch_buffer_grow_preserve did not copy buffer\n");
+	return 1;
+      }
+    for (unsigned i = 7; i < old_length; ++i)
+      if (((char *)buf.data)[i] != '@')
+	{
+	  printf ("scratch_buffer_grow_preserve did not copy buffer (%u)\n",
+		  i);
+	  return 1;
+	}
+    scratch_buffer_free (&buf);
+  }
+  {
+    struct scratch_buffer buf;
+    scratch_buffer_init (&buf);
+    for (int pass = 0; pass < 4; ++pass)
+      {
+	if (!(unchanged_array_size (&buf, 0, 0)
+	      && unchanged_array_size (&buf, 1, 0)
+	      && unchanged_array_size (&buf, 0, 1)
+	      && unchanged_array_size (&buf, -1, 0)
+	      && unchanged_array_size (&buf, 0, -1)
+	      && unchanged_array_size (&buf, 1ULL << 16, 0)
+	      && unchanged_array_size (&buf, 0, 1ULL << 16)
+	      && unchanged_array_size (&buf, (size_t) (1ULL << 32), 0)
+	      && unchanged_array_size (&buf, 0, (size_t) (1ULL << 32))))
+	  return 1;
+	if (!scratch_buffer_grow (&buf))
+	  {
+	    printf ("scratch_buffer_grow_failed (pass %d)\n", pass);
+	  }
+      }
+    scratch_buffer_free (&buf);
+  }
+  {
+    if (!(array_size_must_fail (-1, 1)
+	  && array_size_must_fail (-1, -1)
+	  && array_size_must_fail (1, -1)
+	  && array_size_must_fail (((size_t)-1) / 4, 4)
+	  && array_size_must_fail (4, ((size_t)-1) / 4)))
+	return 1;
+  }
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-trim1.c b/ap/libc/glibc/glibc-2.23/malloc/tst-trim1.c
new file mode 100644
index 0000000..310707e
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-trim1.c
@@ -0,0 +1,56 @@
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define N 10000
+
+static void *arr[N];
+
+static int
+do_test (void)
+{
+  for (int i = 0; i < N; ++i)
+    {
+      size_t size = random () % 16384;
+
+      if ((arr[i] = malloc (size)) == NULL)
+	{
+	nomem:
+	  puts ("not enough memory");
+	  return 0;
+	}
+
+      memset (arr[i], size, size);
+    }
+
+  void *p = malloc (256);
+  if (p == NULL)
+    goto nomem;
+  memset (p, 1, 256);
+
+  puts ("==================================================================");
+
+  for (int i = 0; i < N; ++i)
+    if (i % 13 != 0)
+      free (arr[i]);
+
+  puts ("==================================================================");
+
+  malloc_trim (0);
+
+  puts ("==================================================================");
+
+  p = malloc (30000);
+  if (p == NULL)
+    goto nomem;
+
+  memset (p, 2, 30000);
+
+  malloc_trim (0);
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/ap/libc/glibc/glibc-2.23/malloc/tst-valloc.c b/ap/libc/glibc/glibc-2.23/malloc/tst-valloc.c
new file mode 100644
index 0000000..afcb1e5
--- /dev/null
+++ b/ap/libc/glibc/glibc-2.23/malloc/tst-valloc.c
@@ -0,0 +1,99 @@
+/* Test for valloc.
+   Copyright (C) 2013-2016 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 <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+  ++errors;
+  printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+  void *p;
+  unsigned long pagesize = getpagesize ();
+  unsigned long ptrval;
+  int save;
+
+  errno = 0;
+
+  /* An attempt to allocate a huge value should return NULL and set
+     errno to ENOMEM.  */
+  p = valloc (-1);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("valloc (-1) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("valloc (-1) errno is not set correctly");
+
+  free (p);
+
+  errno = 0;
+
+  /* Test to expose integer overflow in malloc internals from BZ #15856.  */
+  p = valloc (-pagesize);
+
+  save = errno;
+
+  if (p != NULL)
+    merror ("valloc (-pagesize) succeeded.");
+
+  if (p == NULL && save != ENOMEM)
+    merror ("valloc (-pagesize) errno is not set correctly");
+
+  free (p);
+
+  /* A zero-sized allocation should succeed with glibc, returning a
+     non-NULL value.  */
+  p = valloc (0);
+
+  if (p == NULL)
+    merror ("valloc (0) failed.");
+
+  free (p);
+
+  /* Check the alignment of the returned pointer is correct.  */
+  p = valloc (32);
+
+  if (p == NULL)
+    merror ("valloc (32) failed.");
+
+  ptrval = (unsigned long) p;
+
+  if ((ptrval & (pagesize - 1)) != 0)
+    merror ("returned pointer is not page aligned.");
+
+  free (p);
+
+  return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"