|
Packit |
fe9d6e |
/*
|
|
Packit |
fe9d6e |
* Copyright (c) 2005 Hewlett-Packard Development Company, L.P.
|
|
Packit |
fe9d6e |
*
|
|
Packit |
fe9d6e |
* This file may be redistributed and/or modified under the
|
|
Packit |
fe9d6e |
* terms of the GNU General Public License as published by the Free Software
|
|
Packit |
fe9d6e |
* Foundation; either version 2, or (at your option) any later version.
|
|
Packit |
fe9d6e |
*
|
|
Packit |
fe9d6e |
* It is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
Packit |
fe9d6e |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
Packit |
fe9d6e |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License in the
|
|
Packit |
fe9d6e |
* file COPYING for more details.
|
|
Packit |
fe9d6e |
*/
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(HAVE_CONFIG_H)
|
|
Packit |
fe9d6e |
# include "config.h"
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifdef DONT_USE_MMAP /* for testing */
|
|
Packit |
fe9d6e |
# undef HAVE_MMAP
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#define AO_REQUIRE_CAS
|
|
Packit |
fe9d6e |
#include "atomic_ops_malloc.h"
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#include <string.h> /* for ffs, which is assumed reentrant. */
|
|
Packit |
fe9d6e |
#include <stdlib.h>
|
|
Packit |
fe9d6e |
#include <assert.h>
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifdef AO_TRACE_MALLOC
|
|
Packit |
fe9d6e |
# include <stdio.h>
|
|
Packit |
fe9d6e |
# include <pthread.h>
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_ADDRESS_SANITIZER) && !defined(AO_NO_MALLOC_POISON)
|
|
Packit |
fe9d6e |
/* #include "sanitizer/asan_interface.h" */
|
|
Packit |
fe9d6e |
void __asan_poison_memory_region(void *, size_t);
|
|
Packit |
fe9d6e |
void __asan_unpoison_memory_region(void *, size_t);
|
|
Packit |
fe9d6e |
# define ASAN_POISON_MEMORY_REGION(addr, size) \
|
|
Packit |
fe9d6e |
__asan_poison_memory_region(addr, size)
|
|
Packit |
fe9d6e |
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
|
Packit |
fe9d6e |
__asan_unpoison_memory_region(addr, size)
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# define ASAN_POISON_MEMORY_REGION(addr, size) (void)0
|
|
Packit |
fe9d6e |
# define ASAN_UNPOISON_MEMORY_REGION(addr, size) (void)0
|
|
Packit |
fe9d6e |
#endif /* !AO_ADDRESS_SANITIZER */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if (defined(_WIN32_WCE) || defined(__MINGW32CE__)) && !defined(AO_HAVE_abort)
|
|
Packit |
fe9d6e |
# define abort() _exit(-1) /* there is no abort() in WinCE */
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/*
|
|
Packit |
fe9d6e |
* We round up each allocation request to the next power of two
|
|
Packit |
fe9d6e |
* minus one word.
|
|
Packit |
fe9d6e |
* We keep one stack of free objects for each size. Each object
|
|
Packit |
fe9d6e |
* has an initial word (offset -sizeof(AO_t) from the visible pointer)
|
|
Packit |
fe9d6e |
* which contains either
|
|
Packit |
fe9d6e |
* The binary log of the object size in bytes (small objects)
|
|
Packit |
fe9d6e |
* The object size (a multiple of CHUNK_SIZE) for large objects.
|
|
Packit |
fe9d6e |
* The second case only arises if mmap-based allocation is supported.
|
|
Packit |
fe9d6e |
* We align the user-visible part of each object on a GRANULARITY
|
|
Packit |
fe9d6e |
* byte boundary. That means that the actual (hidden) start of
|
|
Packit |
fe9d6e |
* the object starts a word before this boundary.
|
|
Packit |
fe9d6e |
*/
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifndef LOG_MAX_SIZE
|
|
Packit |
fe9d6e |
# define LOG_MAX_SIZE 16
|
|
Packit |
fe9d6e |
/* We assume that 2**LOG_MAX_SIZE is a multiple of page size. */
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifndef ALIGNMENT
|
|
Packit |
fe9d6e |
# define ALIGNMENT 16
|
|
Packit |
fe9d6e |
/* Assumed to be at least sizeof(AO_t). */
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#define CHUNK_SIZE (1 << LOG_MAX_SIZE)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifndef AO_INITIAL_HEAP_SIZE
|
|
Packit |
fe9d6e |
# define AO_INITIAL_HEAP_SIZE (2*(LOG_MAX_SIZE+1)*CHUNK_SIZE)
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
char AO_initial_heap[AO_INITIAL_HEAP_SIZE];
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static volatile AO_t initial_heap_ptr = (AO_t)AO_initial_heap;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(HAVE_MMAP)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#include <sys/types.h>
|
|
Packit |
fe9d6e |
#include <sys/stat.h>
|
|
Packit |
fe9d6e |
#include <fcntl.h>
|
|
Packit |
fe9d6e |
#include <sys/mman.h>
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(MAP_ANONYMOUS) || defined(MAP_ANON)
|
|
Packit |
fe9d6e |
# define USE_MMAP_ANON
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifdef USE_MMAP_FIXED
|
|
Packit |
fe9d6e |
# define GC_MMAP_FLAGS (MAP_FIXED | MAP_PRIVATE)
|
|
Packit |
fe9d6e |
/* Seems to yield better performance on Solaris 2, but can */
|
|
Packit |
fe9d6e |
/* be unreliable if something is already mapped at the address. */
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# define GC_MMAP_FLAGS MAP_PRIVATE
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifdef USE_MMAP_ANON
|
|
Packit |
fe9d6e |
# if defined(CPPCHECK)
|
|
Packit |
fe9d6e |
# define OPT_MAP_ANON 0x20 /* taken from linux */
|
|
Packit |
fe9d6e |
# elif defined(MAP_ANONYMOUS)
|
|
Packit |
fe9d6e |
# define OPT_MAP_ANON MAP_ANONYMOUS
|
|
Packit |
fe9d6e |
# else
|
|
Packit |
fe9d6e |
# define OPT_MAP_ANON MAP_ANON
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# include <unistd.h> /* for close() */
|
|
Packit |
fe9d6e |
# define OPT_MAP_ANON 0
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static volatile AO_t mmap_enabled = 0;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void
|
|
Packit |
fe9d6e |
AO_malloc_enable_mmap(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
# if defined(__sun)
|
|
Packit |
fe9d6e |
AO_store_release(&mmap_enabled, 1);
|
|
Packit |
fe9d6e |
/* Workaround for Sun CC */
|
|
Packit |
fe9d6e |
# else
|
|
Packit |
fe9d6e |
AO_store(&mmap_enabled, 1);
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static char *get_mmaped(size_t sz)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
char * result;
|
|
Packit |
fe9d6e |
# ifdef USE_MMAP_ANON
|
|
Packit |
fe9d6e |
# define zero_fd -1
|
|
Packit |
fe9d6e |
# else
|
|
Packit |
fe9d6e |
int zero_fd;
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
assert(!(sz & (CHUNK_SIZE - 1)));
|
|
Packit |
fe9d6e |
if (!mmap_enabled)
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
# ifndef USE_MMAP_ANON
|
|
Packit |
fe9d6e |
zero_fd = open("/dev/zero", O_RDONLY);
|
|
Packit |
fe9d6e |
if (zero_fd == -1)
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
result = mmap(0, sz, PROT_READ | PROT_WRITE,
|
|
Packit |
fe9d6e |
GC_MMAP_FLAGS | OPT_MAP_ANON, zero_fd, 0/* offset */);
|
|
Packit |
fe9d6e |
# ifndef USE_MMAP_ANON
|
|
Packit |
fe9d6e |
close(zero_fd);
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(result == MAP_FAILED))
|
|
Packit |
fe9d6e |
result = NULL;
|
|
Packit |
fe9d6e |
return result;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#ifndef SIZE_MAX
|
|
Packit |
fe9d6e |
# include <limits.h>
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
#if defined(SIZE_MAX) && !defined(CPPCHECK)
|
|
Packit |
fe9d6e |
# define AO_SIZE_MAX ((size_t)SIZE_MAX)
|
|
Packit |
fe9d6e |
/* Extra cast to workaround some buggy SIZE_MAX definitions. */
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# define AO_SIZE_MAX (~(size_t)0)
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Saturated addition of size_t values. Used to avoid value wrap */
|
|
Packit |
fe9d6e |
/* around on overflow. The arguments should have no side effects. */
|
|
Packit |
fe9d6e |
#define SIZET_SAT_ADD(a, b) \
|
|
Packit |
fe9d6e |
(AO_EXPECT_FALSE((a) >= AO_SIZE_MAX - (b)) ? AO_SIZE_MAX : (a) + (b))
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Allocate an object of size (incl. header) of size > CHUNK_SIZE. */
|
|
Packit |
fe9d6e |
/* sz includes space for an AO_t-sized header. */
|
|
Packit |
fe9d6e |
static char *
|
|
Packit |
fe9d6e |
AO_malloc_large(size_t sz)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
char *result;
|
|
Packit |
fe9d6e |
/* The header will force us to waste ALIGNMENT bytes, incl. header. */
|
|
Packit |
fe9d6e |
/* Round to multiple of CHUNK_SIZE. */
|
|
Packit |
fe9d6e |
sz = SIZET_SAT_ADD(sz, ALIGNMENT + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
|
|
Packit |
fe9d6e |
assert(sz > LOG_MAX_SIZE);
|
|
Packit |
fe9d6e |
result = get_mmaped(sz);
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(NULL == result))
|
|
Packit |
fe9d6e |
return NULL;
|
|
Packit |
fe9d6e |
result += ALIGNMENT;
|
|
Packit |
fe9d6e |
((AO_t *)result)[-1] = (AO_t)sz;
|
|
Packit |
fe9d6e |
return result;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static void
|
|
Packit |
fe9d6e |
AO_free_large(char * p)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t sz = ((AO_t *)p)[-1];
|
|
Packit |
fe9d6e |
if (munmap(p - ALIGNMENT, (size_t)sz) != 0)
|
|
Packit |
fe9d6e |
abort(); /* Programmer error. Not really async-signal-safe, but ... */
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#else /* No MMAP */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void
|
|
Packit |
fe9d6e |
AO_malloc_enable_mmap(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#define get_mmaped(sz) ((char*)0)
|
|
Packit |
fe9d6e |
#define AO_malloc_large(sz) ((char*)0)
|
|
Packit |
fe9d6e |
#define AO_free_large(p) abort()
|
|
Packit |
fe9d6e |
/* Programmer error. Not really async-signal-safe, but ... */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#endif /* No MMAP */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static char *
|
|
Packit |
fe9d6e |
get_chunk(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
char *my_chunk_ptr;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
for (;;) {
|
|
Packit |
fe9d6e |
char *initial_ptr = (char *)AO_load(&initial_heap_ptr);
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
my_chunk_ptr = (char *)(((AO_t)initial_ptr + (ALIGNMENT - 1))
|
|
Packit |
fe9d6e |
& ~(ALIGNMENT - 1));
|
|
Packit |
fe9d6e |
if (initial_ptr != my_chunk_ptr)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
/* Align correctly. If this fails, someone else did it for us. */
|
|
Packit |
fe9d6e |
(void)AO_compare_and_swap_acquire(&initial_heap_ptr,
|
|
Packit |
fe9d6e |
(AO_t)initial_ptr, (AO_t)my_chunk_ptr);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(my_chunk_ptr - AO_initial_heap
|
|
Packit |
fe9d6e |
> AO_INITIAL_HEAP_SIZE - CHUNK_SIZE))
|
|
Packit |
fe9d6e |
break;
|
|
Packit |
fe9d6e |
if (AO_compare_and_swap(&initial_heap_ptr, (AO_t)my_chunk_ptr,
|
|
Packit |
fe9d6e |
(AO_t)(my_chunk_ptr + CHUNK_SIZE))) {
|
|
Packit |
fe9d6e |
return my_chunk_ptr;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* We failed. The initial heap is used up. */
|
|
Packit |
fe9d6e |
my_chunk_ptr = get_mmaped(CHUNK_SIZE);
|
|
Packit |
fe9d6e |
assert (!((AO_t)my_chunk_ptr & (ALIGNMENT-1)));
|
|
Packit |
fe9d6e |
return my_chunk_ptr;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Object free lists. Ith entry corresponds to objects */
|
|
Packit |
fe9d6e |
/* of total size 2**i bytes. */
|
|
Packit |
fe9d6e |
AO_stack_t AO_free_list[LOG_MAX_SIZE+1];
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Break up the chunk, and add it to the object free list for */
|
|
Packit |
fe9d6e |
/* the given size. We have exclusive access to chunk. */
|
|
Packit |
fe9d6e |
static void add_chunk_as(void * chunk, unsigned log_sz)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
size_t ofs, limit;
|
|
Packit |
fe9d6e |
size_t sz = (size_t)1 << log_sz;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
assert (CHUNK_SIZE >= sz);
|
|
Packit |
fe9d6e |
limit = (size_t)CHUNK_SIZE - sz;
|
|
Packit |
fe9d6e |
for (ofs = ALIGNMENT - sizeof(AO_t); ofs <= limit; ofs += sz) {
|
|
Packit |
fe9d6e |
ASAN_POISON_MEMORY_REGION((char *)chunk + ofs + sizeof(AO_t),
|
|
Packit |
fe9d6e |
sz - sizeof(AO_t));
|
|
Packit |
fe9d6e |
AO_stack_push(&AO_free_list[log_sz], (AO_t *)((char *)chunk + ofs));
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
static const unsigned char msbs[16] = {
|
|
Packit |
fe9d6e |
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4
|
|
Packit |
fe9d6e |
};
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Return the position of the most significant set bit in the */
|
|
Packit |
fe9d6e |
/* argument. */
|
|
Packit |
fe9d6e |
/* We follow the conventions of ffs(), i.e. the least */
|
|
Packit |
fe9d6e |
/* significant bit is number one. */
|
|
Packit |
fe9d6e |
static unsigned msb(size_t s)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
unsigned result = 0;
|
|
Packit |
fe9d6e |
if ((s & 0xff) != s) {
|
|
Packit |
fe9d6e |
# if (__SIZEOF_SIZE_T__ == 8) && !defined(CPPCHECK)
|
|
Packit |
fe9d6e |
unsigned v = (unsigned)(s >> 32);
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(v != 0))
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
s = v;
|
|
Packit |
fe9d6e |
result += 32;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
# elif __SIZEOF_SIZE_T__ == 4
|
|
Packit |
fe9d6e |
/* No op. */
|
|
Packit |
fe9d6e |
# else
|
|
Packit |
fe9d6e |
unsigned v;
|
|
Packit |
fe9d6e |
/* The following is a tricky code ought to be equivalent to */
|
|
Packit |
fe9d6e |
/* "(v = s >> 32) != 0" but suppresses warnings on 32-bit arch's. */
|
|
Packit |
fe9d6e |
# define SIZEOF_SIZE_T_GT_4 (sizeof(size_t) > 4)
|
|
Packit |
fe9d6e |
if (SIZEOF_SIZE_T_GT_4
|
|
Packit |
fe9d6e |
&& (v = (unsigned)(s >> (SIZEOF_SIZE_T_GT_4 ? 32 : 0))) != 0)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
s = v;
|
|
Packit |
fe9d6e |
result += 32;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
# endif /* !defined(__SIZEOF_SIZE_T__) */
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE((s >> 16) != 0))
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
s >>= 16;
|
|
Packit |
fe9d6e |
result += 16;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
if ((s >> 8) != 0)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
s >>= 8;
|
|
Packit |
fe9d6e |
result += 8;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
if (s > 15)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
s >>= 4;
|
|
Packit |
fe9d6e |
result += 4;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
result += msbs[s];
|
|
Packit |
fe9d6e |
return result;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void *
|
|
Packit |
fe9d6e |
AO_malloc(size_t sz)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t *result;
|
|
Packit |
fe9d6e |
unsigned log_sz;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(sz > CHUNK_SIZE - sizeof(AO_t)))
|
|
Packit |
fe9d6e |
return AO_malloc_large(sz);
|
|
Packit |
fe9d6e |
log_sz = msb(sz + (sizeof(AO_t) - 1));
|
|
Packit |
fe9d6e |
assert(log_sz <= LOG_MAX_SIZE);
|
|
Packit |
fe9d6e |
assert(((size_t)1 << log_sz) >= sz + sizeof(AO_t));
|
|
Packit |
fe9d6e |
result = AO_stack_pop(AO_free_list+log_sz);
|
|
Packit |
fe9d6e |
while (AO_EXPECT_FALSE(NULL == result)) {
|
|
Packit |
fe9d6e |
void * chunk = get_chunk();
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(NULL == chunk))
|
|
Packit |
fe9d6e |
return NULL;
|
|
Packit |
fe9d6e |
add_chunk_as(chunk, log_sz);
|
|
Packit |
fe9d6e |
result = AO_stack_pop(AO_free_list+log_sz);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
*result = log_sz;
|
|
Packit |
fe9d6e |
# ifdef AO_TRACE_MALLOC
|
|
Packit |
fe9d6e |
fprintf(stderr, "%p: AO_malloc(%lu) = %p\n",
|
|
Packit |
fe9d6e |
(void *)pthread_self(), (unsigned long)sz, (void *)(result + 1));
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
ASAN_UNPOISON_MEMORY_REGION(result + 1, sz);
|
|
Packit |
fe9d6e |
return result + 1;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void
|
|
Packit |
fe9d6e |
AO_free(void *p)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t *base;
|
|
Packit |
fe9d6e |
int log_sz;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(NULL == p))
|
|
Packit |
fe9d6e |
return;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
base = (AO_t *)p - 1;
|
|
Packit |
fe9d6e |
log_sz = (int)(*base);
|
|
Packit |
fe9d6e |
# ifdef AO_TRACE_MALLOC
|
|
Packit |
fe9d6e |
fprintf(stderr, "%p: AO_free(%p sz:%lu)\n", (void *)pthread_self(), p,
|
|
Packit |
fe9d6e |
log_sz > LOG_MAX_SIZE ? (unsigned)log_sz : 1UL << log_sz);
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
if (AO_EXPECT_FALSE(log_sz > LOG_MAX_SIZE)) {
|
|
Packit |
fe9d6e |
AO_free_large(p);
|
|
Packit |
fe9d6e |
} else {
|
|
Packit |
fe9d6e |
ASAN_POISON_MEMORY_REGION(base + 1, ((size_t)1 << log_sz) - sizeof(AO_t));
|
|
Packit |
fe9d6e |
AO_stack_push(AO_free_list + log_sz, base);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
}
|