|
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 |
*/
|