Blame malloc/hooks.c

Packit 6c4009
/* Malloc implementation for multiple threads without lock contention.
Packit 6c4009
   Copyright (C) 2001-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public License as
Packit 6c4009
   published by the Free Software Foundation; either version 2.1 of the
Packit 6c4009
   License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; see the file COPYING.LIB.  If
Packit 6c4009
   not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* What to do if the standard debugging hooks are in place and a
Packit 6c4009
   corrupt pointer is detected: do nothing (0), print an error message
Packit 6c4009
   (1), or call abort() (2). */
Packit 6c4009
Packit 6c4009
/* Hooks for debugging versions.  The initial hooks just call the
Packit 6c4009
   initialization routine, then do the normal work. */
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
malloc_hook_ini (size_t sz, const void *caller)
Packit 6c4009
{
Packit 6c4009
  __malloc_hook = NULL;
Packit 6c4009
  ptmalloc_init ();
Packit 6c4009
  return __libc_malloc (sz);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
realloc_hook_ini (void *ptr, size_t sz, const void *caller)
Packit 6c4009
{
Packit 6c4009
  __malloc_hook = NULL;
Packit 6c4009
  __realloc_hook = NULL;
Packit 6c4009
  ptmalloc_init ();
Packit 6c4009
  return __libc_realloc (ptr, sz);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
Packit 6c4009
{
Packit 6c4009
  __memalign_hook = NULL;
Packit 6c4009
  ptmalloc_init ();
Packit 6c4009
  return __libc_memalign (alignment, sz);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Whether we are using malloc checking.  */
Packit 6c4009
static int using_malloc_checking;
Packit 6c4009
Packit 6c4009
/* Activate a standard set of debugging hooks. */
Packit 6c4009
void
Packit 6c4009
__malloc_check_init (void)
Packit 6c4009
{
Packit 6c4009
  using_malloc_checking = 1;
Packit 6c4009
  __malloc_hook = malloc_check;
Packit 6c4009
  __free_hook = free_check;
Packit 6c4009
  __realloc_hook = realloc_check;
Packit 6c4009
  __memalign_hook = memalign_check;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* A simple, standard set of debugging hooks.  Overhead is `only' one
Packit 6c4009
   byte per chunk; still this will catch most cases of double frees or
Packit 6c4009
   overruns.  The goal here is to avoid obscure crashes due to invalid
Packit 6c4009
   usage, unlike in the MALLOC_DEBUG code. */
Packit 6c4009
Packit 6c4009
static unsigned char
Packit 6c4009
magicbyte (const void *p)
Packit 6c4009
{
Packit 6c4009
  unsigned char magic;
Packit 6c4009
Packit 6c4009
  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
Packit 6c4009
  /* Do not return 1.  See the comment in mem2mem_check().  */
Packit 6c4009
  if (magic == 1)
Packit 6c4009
    ++magic;
Packit 6c4009
  return magic;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
Packit 6c4009
   highest address of the chunk, downwards.  The end of each block tells
Packit 6c4009
   us the size of that block, up to the actual size of the requested
Packit 6c4009
   memory.  Our magic byte is right at the end of the requested size, so we
Packit 6c4009
   must reach it with this iteration, otherwise we have witnessed a memory
Packit 6c4009
   corruption.  */
Packit 6c4009
static size_t
Packit 6c4009
malloc_check_get_size (mchunkptr p)
Packit 6c4009
{
Packit 6c4009
  size_t size;
Packit 6c4009
  unsigned char c;
Packit 6c4009
  unsigned char magic = magicbyte (p);
Packit 6c4009
Packit 6c4009
  assert (using_malloc_checking == 1);
Packit 6c4009
Packit 6c4009
  for (size = chunksize (p) - 1 + (chunk_is_mmapped (p) ? 0 : SIZE_SZ);
Packit 6c4009
       (c = ((unsigned char *) p)[size]) != magic;
Packit 6c4009
       size -= c)
Packit 6c4009
    {
Packit 6c4009
      if (c <= 0 || size < (c + 2 * SIZE_SZ))
Packit 6c4009
	malloc_printerr ("malloc_check_get_size: memory corruption");
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* chunk2mem size.  */
Packit 6c4009
  return size - 2 * SIZE_SZ;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Instrument a chunk with overrun detector byte(s) and convert it
Packit 6c4009
   into a user pointer with requested size req_sz. */
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
mem2mem_check (void *ptr, size_t req_sz)
Packit 6c4009
{
Packit 6c4009
  mchunkptr p;
Packit 6c4009
  unsigned char *m_ptr = ptr;
Packit 6c4009
  size_t max_sz, block_sz, i;
Packit 6c4009
  unsigned char magic;
Packit 6c4009
Packit 6c4009
  if (!ptr)
Packit 6c4009
    return ptr;
Packit 6c4009
Packit 6c4009
  p = mem2chunk (ptr);
Packit 6c4009
  magic = magicbyte (p);
Packit 6c4009
  max_sz = chunksize (p) - 2 * SIZE_SZ;
Packit 6c4009
  if (!chunk_is_mmapped (p))
Packit 6c4009
    max_sz += SIZE_SZ;
Packit 6c4009
  for (i = max_sz - 1; i > req_sz; i -= block_sz)
Packit 6c4009
    {
Packit 6c4009
      block_sz = MIN (i - req_sz, 0xff);
Packit 6c4009
      /* Don't allow the magic byte to appear in the chain of length bytes.
Packit 6c4009
         For the following to work, magicbyte cannot return 0x01.  */
Packit 6c4009
      if (block_sz == magic)
Packit 6c4009
        --block_sz;
Packit 6c4009
Packit 6c4009
      m_ptr[i] = block_sz;
Packit 6c4009
    }
Packit 6c4009
  m_ptr[req_sz] = magic;
Packit 6c4009
  return (void *) m_ptr;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Convert a pointer to be free()d or realloc()ed to a valid chunk
Packit 6c4009
   pointer.  If the provided pointer is not valid, return NULL. */
Packit 6c4009
Packit 6c4009
static mchunkptr
Packit 6c4009
mem2chunk_check (void *mem, unsigned char **magic_p)
Packit 6c4009
{
Packit 6c4009
  mchunkptr p;
Packit 6c4009
  INTERNAL_SIZE_T sz, c;
Packit 6c4009
  unsigned char magic;
Packit 6c4009
Packit 6c4009
  if (!aligned_OK (mem))
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  p = mem2chunk (mem);
Packit 6c4009
  sz = chunksize (p);
Packit 6c4009
  magic = magicbyte (p);
Packit 6c4009
  if (!chunk_is_mmapped (p))
Packit 6c4009
    {
Packit 6c4009
      /* Must be a chunk in conventional heap memory. */
Packit 6c4009
      int contig = contiguous (&main_arena);
Packit 6c4009
      if ((contig &&
Packit 6c4009
           ((char *) p < mp_.sbrk_base ||
Packit 6c4009
            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
Packit 6c4009
          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
Packit 6c4009
          (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 ||
Packit 6c4009
                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
Packit 6c4009
                               next_chunk (prev_chunk (p)) != p)))
Packit 6c4009
        return NULL;
Packit 6c4009
Packit 6c4009
      for (sz += SIZE_SZ - 1; (c = ((unsigned char *) p)[sz]) != magic; sz -= c)
Packit 6c4009
        {
Packit 6c4009
          if (c == 0 || sz < (c + 2 * SIZE_SZ))
Packit 6c4009
            return NULL;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
Packit 6c4009
Packit 6c4009
      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
Packit 6c4009
         alignment relative to the beginning of a page.  Check this
Packit 6c4009
         first. */
Packit 6c4009
      offset = (unsigned long) mem & page_mask;
Packit 6c4009
      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
Packit 6c4009
           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
Packit 6c4009
           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
Packit 6c4009
           offset < 0x2000) ||
Packit 6c4009
          !chunk_is_mmapped (p) || prev_inuse (p) ||
Packit 6c4009
          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
Packit 6c4009
          ((prev_size (p) + sz) & page_mask) != 0)
Packit 6c4009
        return NULL;
Packit 6c4009
Packit 6c4009
      for (sz -= 1; (c = ((unsigned char *) p)[sz]) != magic; sz -= c)
Packit 6c4009
        {
Packit 6c4009
          if (c == 0 || sz < (c + 2 * SIZE_SZ))
Packit 6c4009
            return NULL;
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
  ((unsigned char *) p)[sz] ^= 0xFF;
Packit 6c4009
  if (magic_p)
Packit 6c4009
    *magic_p = (unsigned char *) p + sz;
Packit 6c4009
  return p;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Check for corruption of the top chunk.  */
Packit 6c4009
static void
Packit 6c4009
top_check (void)
Packit 6c4009
{
Packit 6c4009
  mchunkptr t = top (&main_arena);
Packit 6c4009
Packit 6c4009
  if (t == initial_top (&main_arena) ||
Packit 6c4009
      (!chunk_is_mmapped (t) &&
Packit 6c4009
       chunksize (t) >= MINSIZE &&
Packit 6c4009
       prev_inuse (t) &&
Packit 6c4009
       (!contiguous (&main_arena) ||
Packit 6c4009
        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  malloc_printerr ("malloc: top chunk is corrupt");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
malloc_check (size_t sz, const void *caller)
Packit 6c4009
{
Packit 6c4009
  void *victim;
Packit 6c4009
Packit 6c4009
  if (sz + 1 == 0)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOMEM);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (main_arena.mutex);
Packit 6c4009
  top_check ();
Packit 6c4009
  victim = _int_malloc (&main_arena, sz + 1);
Packit 6c4009
  __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
  return mem2mem_check (victim, sz);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
free_check (void *mem, const void *caller)
Packit 6c4009
{
Packit 6c4009
  mchunkptr p;
Packit 6c4009
Packit 6c4009
  if (!mem)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (main_arena.mutex);
Packit 6c4009
  p = mem2chunk_check (mem, NULL);
Packit 6c4009
  if (!p)
Packit 6c4009
    malloc_printerr ("free(): invalid pointer");
Packit 6c4009
  if (chunk_is_mmapped (p))
Packit 6c4009
    {
Packit 6c4009
      __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
      munmap_chunk (p);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
  _int_free (&main_arena, p, 1);
Packit 6c4009
  __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
realloc_check (void *oldmem, size_t bytes, const void *caller)
Packit 6c4009
{
Packit 6c4009
  INTERNAL_SIZE_T nb;
Packit 6c4009
  void *newmem = 0;
Packit 6c4009
  unsigned char *magic_p;
Packit 6c4009
Packit 6c4009
  if (bytes + 1 == 0)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOMEM);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  if (oldmem == 0)
Packit 6c4009
    return malloc_check (bytes, NULL);
Packit 6c4009
Packit 6c4009
  if (bytes == 0)
Packit 6c4009
    {
Packit 6c4009
      free_check (oldmem, NULL);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  __libc_lock_lock (main_arena.mutex);
Packit 6c4009
  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
Packit 6c4009
  __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
  if (!oldp)
Packit 6c4009
    malloc_printerr ("realloc(): invalid pointer");
Packit 6c4009
  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
Packit 6c4009
Packit 6c4009
  checked_request2size (bytes + 1, nb);
Packit 6c4009
  __libc_lock_lock (main_arena.mutex);
Packit 6c4009
Packit 6c4009
  if (chunk_is_mmapped (oldp))
Packit 6c4009
    {
Packit 6c4009
#if HAVE_MREMAP
Packit 6c4009
      mchunkptr newp = mremap_chunk (oldp, nb);
Packit 6c4009
      if (newp)
Packit 6c4009
        newmem = chunk2mem (newp);
Packit 6c4009
      else
Packit 6c4009
#endif
Packit 6c4009
      {
Packit 6c4009
        /* Note the extra SIZE_SZ overhead. */
Packit 6c4009
        if (oldsize - SIZE_SZ >= nb)
Packit 6c4009
          newmem = oldmem; /* do nothing */
Packit 6c4009
        else
Packit 6c4009
          {
Packit 6c4009
            /* Must alloc, copy, free. */
Packit 6c4009
	    top_check ();
Packit 6c4009
	    newmem = _int_malloc (&main_arena, bytes + 1);
Packit 6c4009
            if (newmem)
Packit 6c4009
              {
Packit 6c4009
                memcpy (newmem, oldmem, oldsize - 2 * SIZE_SZ);
Packit 6c4009
                munmap_chunk (oldp);
Packit 6c4009
              }
Packit 6c4009
          }
Packit 6c4009
      }
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      top_check ();
Packit 6c4009
      INTERNAL_SIZE_T nb;
Packit 6c4009
      checked_request2size (bytes + 1, nb);
Packit 6c4009
      newmem = _int_realloc (&main_arena, oldp, oldsize, nb);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
#if __GNUC_PREREQ (7, 0)
Packit 6c4009
  /* GCC 7 warns about magic_p may be used uninitialized.  But we never
Packit 6c4009
     reach here if magic_p is uninitialized.  */
Packit 6c4009
  DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
Packit 6c4009
#endif
Packit 6c4009
  /* mem2chunk_check changed the magic byte in the old chunk.
Packit 6c4009
     If newmem is NULL, then the old chunk will still be used though,
Packit 6c4009
     so we need to invert that change here.  */
Packit 6c4009
  if (newmem == NULL)
Packit 6c4009
    *magic_p ^= 0xFF;
Packit 6c4009
  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
Packit 6c4009
  return mem2mem_check (newmem, bytes);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void *
Packit 6c4009
memalign_check (size_t alignment, size_t bytes, const void *caller)
Packit 6c4009
{
Packit 6c4009
  void *mem;
Packit 6c4009
Packit 6c4009
  if (alignment <= MALLOC_ALIGNMENT)
Packit 6c4009
    return malloc_check (bytes, NULL);
Packit 6c4009
Packit 6c4009
  if (alignment < MINSIZE)
Packit 6c4009
    alignment = MINSIZE;
Packit 6c4009
Packit 6c4009
  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
Packit 6c4009
     power of 2 and will cause overflow in the check below.  */
Packit 6c4009
  if (alignment > SIZE_MAX / 2 + 1)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Check for overflow.  */
Packit 6c4009
  if (bytes > SIZE_MAX - alignment - MINSIZE)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOMEM);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Make sure alignment is power of 2.  */
Packit 6c4009
  if (!powerof2 (alignment))
Packit 6c4009
    {
Packit 6c4009
      size_t a = MALLOC_ALIGNMENT * 2;
Packit 6c4009
      while (a < alignment)
Packit 6c4009
        a <<= 1;
Packit 6c4009
      alignment = a;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (main_arena.mutex);
Packit 6c4009
  top_check ();
Packit 6c4009
  mem = _int_memalign (&main_arena, alignment, bytes + 1);
Packit 6c4009
  __libc_lock_unlock (main_arena.mutex);
Packit 6c4009
  return mem2mem_check (mem, bytes);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
Packit 6c4009
Packit 6c4009
/* Support for restoring dumped heaps contained in historic Emacs
Packit 6c4009
   executables.  The heap saving feature (malloc_get_state) is no
Packit 6c4009
   longer implemented in this version of glibc, but we have a heap
Packit 6c4009
   rewriter in malloc_set_state which transforms the heap into a
Packit 6c4009
   version compatible with current malloc.  */
Packit 6c4009
Packit 6c4009
#define MALLOC_STATE_MAGIC   0x444c4541l
Packit 6c4009
#define MALLOC_STATE_VERSION (0 * 0x100l + 5l) /* major*0x100 + minor */
Packit 6c4009
Packit 6c4009
struct malloc_save_state
Packit 6c4009
{
Packit 6c4009
  long magic;
Packit 6c4009
  long version;
Packit 6c4009
  mbinptr av[NBINS * 2 + 2];
Packit 6c4009
  char *sbrk_base;
Packit 6c4009
  int sbrked_mem_bytes;
Packit 6c4009
  unsigned long trim_threshold;
Packit 6c4009
  unsigned long top_pad;
Packit 6c4009
  unsigned int n_mmaps_max;
Packit 6c4009
  unsigned long mmap_threshold;
Packit 6c4009
  int check_action;
Packit 6c4009
  unsigned long max_sbrked_mem;
Packit 6c4009
  unsigned long max_total_mem;	/* Always 0, for backwards compatibility.  */
Packit 6c4009
  unsigned int n_mmaps;
Packit 6c4009
  unsigned int max_n_mmaps;
Packit 6c4009
  unsigned long mmapped_mem;
Packit 6c4009
  unsigned long max_mmapped_mem;
Packit 6c4009
  int using_malloc_checking;
Packit 6c4009
  unsigned long max_fast;
Packit 6c4009
  unsigned long arena_test;
Packit 6c4009
  unsigned long arena_max;
Packit 6c4009
  unsigned long narenas;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Dummy implementation which always fails.  We need to provide this
Packit 6c4009
   symbol so that existing Emacs binaries continue to work with
Packit 6c4009
   BIND_NOW.  */
Packit 6c4009
void *
Packit 6c4009
attribute_compat_text_section
Packit 6c4009
malloc_get_state (void)
Packit 6c4009
{
Packit 6c4009
  __set_errno (ENOSYS);
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
compat_symbol (libc, malloc_get_state, malloc_get_state, GLIBC_2_0);
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
attribute_compat_text_section
Packit 6c4009
malloc_set_state (void *msptr)
Packit 6c4009
{
Packit 6c4009
  struct malloc_save_state *ms = (struct malloc_save_state *) msptr;
Packit 6c4009
Packit 6c4009
  if (ms->magic != MALLOC_STATE_MAGIC)
Packit 6c4009
    return -1;
Packit 6c4009
Packit 6c4009
  /* Must fail if the major version is too high. */
Packit 6c4009
  if ((ms->version & ~0xffl) > (MALLOC_STATE_VERSION & ~0xffl))
Packit 6c4009
    return -2;
Packit 6c4009
Packit 6c4009
  /* We do not need to perform locking here because malloc_set_state
Packit 6c4009
     must be called before the first call into the malloc subsytem
Packit 6c4009
     (usually via __malloc_initialize_hook).  pthread_create always
Packit 6c4009
     calls calloc and thus must be called only afterwards, so there
Packit 6c4009
     cannot be more than one thread when we reach this point.  */
Packit 6c4009
Packit 6c4009
  /* Disable the malloc hooks (and malloc checking).  */
Packit 6c4009
  __malloc_hook = NULL;
Packit 6c4009
  __realloc_hook = NULL;
Packit 6c4009
  __free_hook = NULL;
Packit 6c4009
  __memalign_hook = NULL;
Packit 6c4009
  using_malloc_checking = 0;
Packit 6c4009
Packit 6c4009
  /* Patch the dumped heap.  We no longer try to integrate into the
Packit 6c4009
     existing heap.  Instead, we mark the existing chunks as mmapped.
Packit 6c4009
     Together with the update to dumped_main_arena_start and
Packit 6c4009
     dumped_main_arena_end, realloc and free will recognize these
Packit 6c4009
     chunks as dumped fake mmapped chunks and never free them.  */
Packit 6c4009
Packit 6c4009
  /* Find the chunk with the lowest address with the heap.  */
Packit 6c4009
  mchunkptr chunk = NULL;
Packit 6c4009
  {
Packit 6c4009
    size_t *candidate = (size_t *) ms->sbrk_base;
Packit 6c4009
    size_t *end = (size_t *) (ms->sbrk_base + ms->sbrked_mem_bytes);
Packit 6c4009
    while (candidate < end)
Packit 6c4009
      if (*candidate != 0)
Packit 6c4009
	{
Packit 6c4009
	  chunk = mem2chunk ((void *) (candidate + 1));
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	++candidate;
Packit 6c4009
  }
Packit 6c4009
  if (chunk == NULL)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  /* Iterate over the dumped heap and patch the chunks so that they
Packit 6c4009
     are treated as fake mmapped chunks.  */
Packit 6c4009
  mchunkptr top = ms->av[2];
Packit 6c4009
  while (chunk < top)
Packit 6c4009
    {
Packit 6c4009
      if (inuse (chunk))
Packit 6c4009
	{
Packit 6c4009
	  /* Mark chunk as mmapped, to trigger the fallback path.  */
Packit 6c4009
	  size_t size = chunksize (chunk);
Packit 6c4009
	  set_head (chunk, size | IS_MMAPPED);
Packit 6c4009
	}
Packit 6c4009
      chunk = next_chunk (chunk);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The dumped fake mmapped chunks all lie in this address range.  */
Packit 6c4009
  dumped_main_arena_start = (mchunkptr) ms->sbrk_base;
Packit 6c4009
  dumped_main_arena_end = top;
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
compat_symbol (libc, malloc_set_state, malloc_set_state, GLIBC_2_0);
Packit 6c4009
Packit 6c4009
#endif	/* SHLIB_COMPAT */
Packit 6c4009
Packit 6c4009
/*
Packit 6c4009
 * Local variables:
Packit 6c4009
 * c-basic-offset: 2
Packit 6c4009
 * End:
Packit 6c4009
 */