#ifndef _DEFAULT_SOURCE
#define _DEFAULT_SOURCE
#endif
#include "mimalloc.h"
#include "mimalloc/internal.h"
#include "mimalloc/atomic.h"
#include "mimalloc/prim-tls.h"
#include <string.h>
#include <stdlib.h>
#define MI_IN_ALLOC_C
#include "alloc-override.c"
#include "free.c"
#undef MI_IN_ALLOC_C
#if MI_PADDING
static mi_decl_noinline void mi_page_block_setup_padding(mi_page_t* page, mi_block_t* block, size_t size) mi_attr_noexcept {
const size_t bsize = mi_page_usable_block_size(page);
mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + bsize);
const ptrdiff_t delta = ((uint8_t*)padding - (uint8_t*)block - (size - MI_PADDING_SIZE));
mi_assert_internal(delta >= 0 && bsize >= (size - MI_PADDING_SIZE + delta));
mi_track_mem_defined(padding,sizeof(mi_padding_t)); padding->canary = mi_ptr_encode_canary(page,block,page->keys);
padding->delta = (uint32_t)(delta);
#if MI_PADDING_CHECK_BYTES
if (!mi_page_is_huge(page)) {
uint8_t* fill = (uint8_t*)padding - delta;
const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); for (size_t i = 0; i < maxpad; i++) { fill[i] = MI_DEBUG_PADDING; }
}
#endif
}
#endif
static mi_decl_forceinline void* mi_page_malloc_zero(mi_theap_t* theap, mi_page_t* page, size_t size, size_t sample_countdown, bool zero, mi_page_t** ppage) mi_attr_noexcept
{
if (page->block_size != 0) { mi_assert_internal(mi_page_block_size(page) >= size);
mi_assert_internal(_mi_is_aligned(mi_page_slice_start(page), MI_PAGE_ALIGN));
mi_assert_internal(_mi_ptr_page(mi_page_start(page))==page);
mi_assert_internal(mi_page_alloc_count(page) + mi_page_last_used(page) >= mi_page_used(page));
}
mi_block_t* const block = page->free;
mi_used_t xused = page->xused;
xused.used_alloc += 0x10001; #if defined(__GNUC__)
__asm("" : : : "memory" ); #endif
if (block == NULL) {
return _mi_malloc_generic(theap, size, (zero ? 1 : 0), ppage);
}
mi_assert_internal(block != NULL && _mi_ptr_page(block) == page);
if (ppage != NULL) { *ppage = page; };
mi_block_t* next = mi_block_next(page,block);
mi_track_mem_undefined(block,sizeof(*block));
#if MI_SECURE
if (!zero) block->next = 0; #endif
page->free = next;
page->xused = xused;
mi_assert_internal(page->free == NULL || _mi_ptr_page(page->free) == page);
mi_assert_internal(page->block_size < MI_MAX_ALIGN_SIZE || _mi_is_aligned(block, MI_MAX_ALIGN_SIZE));
#if MI_SAMPLE==2
const size_t req_size = size - MI_PADDING_SIZE;
mi_assert_internal(theap->sample_countdown == sample_countdown); mi_assert_internal(theap->sample_countdown >= req_size);
theap->sample_countdown = sample_countdown - req_size;
#else
MI_UNUSED(sample_countdown);
#endif
#if MI_STATS>=2
mi_theap_stat_counter_increase(theap,malloc_requested,size - MI_PADDING_SIZE);
#endif
#if MI_DEBUG>3
if (page->free_is_zero && size > sizeof(*block)) {
mi_assert_expensive(mi_mem_is_zero(block+1,size - sizeof(*block)));
}
#endif
const size_t bsize = mi_page_usable_block_size(page);
mi_track_mem_undefined(block, bsize);
mi_assert_internal(mi_page_alloc_count(page) + mi_page_last_used(page) >= mi_page_used(page));
#if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN
if mi_likely(!zero && !mi_page_is_huge(page)) { memset(block, MI_DEBUG_UNINIT, bsize); }
#endif
if mi_unlikely(zero) {
if (!page->free_is_zero) {
mi_assert_internal(bsize%MI_SIZE_SIZE == 0);
#if !MI_PADDING
return #endif
_mi_memzero_block(block,bsize);
}
else {
block->next = 0;
mi_track_mem_defined(block, bsize);
}
}
#if MI_PADDING
mi_page_block_setup_padding(page,block,size);
#endif
return block;
}
extern void* _mi_page_malloc_zero(mi_theap_t* theap, mi_page_t* page, size_t size, bool zero) mi_attr_noexcept {
return mi_page_malloc_zero(theap, page, size, theap->sample_countdown, zero, NULL);
}
static mi_decl_forceinline mi_decl_restrict void* mi_theap_nonnull_xmalloc_small_zero(mi_theap_t* theap, size_t xsize, bool is_wsize, bool zero, mi_page_t** ppage) mi_attr_noexcept
{
size_t size = (is_wsize ? xsize * MI_SIZE_SIZE : xsize);
mi_assert(theap != NULL);
mi_assert(size <= MI_SMALL_SIZE_MAX);
#if MI_DEBUG
mi_assert(mi_theap_matches_thread(theap)); #endif
#if (MI_PADDING)
if mi_unlikely(xsize == 0) { xsize = (is_wsize ? 1 : MI_SIZE_SIZE); size += MI_SIZE_SIZE; }
#endif
#if MI_SAMPLE==2
if mi_unlikely(mi_theap_should_sample(theap,size)) { return _mi_theap_malloc_sampled(theap,size,zero,ppage); }
#endif
mi_page_t* page = _mi_theap_get_free_small_page(theap, xsize + (is_wsize ? MI_PADDING_WSIZE : MI_PADDING_SIZE), is_wsize);
void* const p = mi_page_malloc_zero(theap, page, size + MI_PADDING_SIZE, theap->sample_countdown, zero, ppage);
mi_track_malloc(p,size,zero);
#if MI_DEBUG>3
if (p != NULL && zero) {
mi_assert_expensive(mi_mem_is_zero(p, size));
}
#endif
return p;
}
static mi_decl_forceinline void* mi_theap_malloc_generic(mi_theap_t* theap, size_t size, bool zero, size_t huge_alignment, mi_page_t** ppage) mi_attr_noexcept
{
#if !MI_THEAP_INITASNULL
mi_assert(theap!=NULL);
#endif
mi_assert(mi_theap_matches_thread(theap)); mi_assert((huge_alignment & 1)==0);
void* const p = _mi_malloc_generic(theap, size + MI_PADDING_SIZE, (zero ? 1 : 0) | huge_alignment, ppage); mi_track_malloc(p, size, zero);
#if MI_DEBUG>3
if (p != NULL && zero) {
mi_assert_expensive(mi_mem_is_zero(p, size));
}
#endif
return p;
}
static mi_decl_forceinline mi_decl_restrict void* mi_theap_xmalloc_small_zero(mi_theap_t* theap, size_t xsize, bool is_wsize, bool zero, mi_page_t** ppage) mi_attr_noexcept {
#if !MI_THEAP_INITASNULL
return mi_theap_nonnull_xmalloc_small_zero(theap, xsize, is_wsize, zero, ppage);
#else
if (theap!=NULL) {
return mi_theap_nonnull_xmalloc_small_zero(theap, xsize, is_wsize, zero, ppage);
}
else {
return mi_theap_malloc_generic(theap, (is_wsize ? xsize * MI_SIZE_SIZE : xsize), zero, 0, ppage); }
#endif
}
mi_decl_nodiscard extern inline mi_decl_restrict void* mi_theap_malloc_small(mi_theap_t* theap, size_t size) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_xmalloc_small_zero(theap, size, false, false, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wmalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_xmalloc_small_zero(theap, wsize, true, false, NULL);
}
mi_decl_nodiscard extern inline mi_decl_restrict void* mi_theap_zalloc_small(mi_theap_t* theap, size_t size) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_xmalloc_small_zero(theap, size, false, true, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_theap_wzalloc_small(mi_theap_t* theap, size_t wsize) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_xmalloc_small_zero(theap, wsize, true, true, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_malloc_small(size_t size) mi_attr_noexcept {
return mi_theap_xmalloc_small_zero(_mi_theap_default(), size, false, false, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_zalloc_small(size_t size) mi_attr_noexcept {
return mi_theap_xmalloc_small_zero(_mi_theap_default(), size, false, true, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_wmalloc_small(size_t wsize) mi_attr_noexcept {
return mi_theap_xmalloc_small_zero(_mi_theap_default(), wsize, true, false, NULL );
}
mi_decl_nodiscard mi_decl_restrict void* mi_wzalloc_small(size_t wsize) mi_attr_noexcept {
return mi_theap_xmalloc_small_zero(_mi_theap_default(), wsize, true, true, NULL);
}
mi_decl_nodiscard static mi_decl_noinline mi_decl_restrict void* mi_heap_init_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept {
return mi_theap_malloc_small(_mi_heap_theap_get_or_init(heap), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept {
mi_theap_t* const theap = _mi_heap_theap_cached(heap);
if mi_likely(theap!=NULL) { return mi_theap_malloc_small(theap, size); }
else { return mi_heap_init_malloc_small(heap, size); }
}
mi_decl_nodiscard static mi_decl_noinline mi_decl_restrict void* mi_heap_init_zalloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept {
return mi_theap_zalloc_small(_mi_heap_theap_get_or_init(heap), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_zalloc_small(mi_heap_t* heap, size_t size) mi_attr_noexcept {
mi_theap_t* const theap = _mi_heap_theap_cached(heap);
if mi_likely(theap!=NULL) { return mi_theap_zalloc_small(theap, size); }
else { return mi_heap_init_zalloc_small(heap, size); }
}
mi_decl_nodiscard static mi_decl_forceinline mi_decl_restrict void* mi_theap_nonnull_malloc_zero(mi_theap_t* theap, size_t size, bool zero, size_t huge_alignment, mi_page_t** ppage) mi_attr_noexcept {
mi_assert(theap!=NULL);
if mi_likely(size <= MI_SMALL_SIZE_MAX) {
mi_assert_internal(huge_alignment == 0);
return mi_theap_nonnull_xmalloc_small_zero(theap, size, false, zero, ppage);
}
else {
return mi_theap_malloc_generic(theap, size, zero, huge_alignment, ppage);
}
}
mi_decl_nodiscard extern mi_decl_forceinline mi_decl_restrict void* _mi_theap_malloc_zero(mi_theap_t* theap, size_t size, bool zero, size_t huge_alignment, mi_page_t** ppage) mi_attr_noexcept {
#if MI_THEAP_INITASNULL
if mi_likely(theap!=NULL && size <= MI_SMALL_SIZE_MAX)
#else
if mi_likely(size <= MI_SMALL_SIZE_MAX)
#endif
{
mi_assert_internal(huge_alignment == 0);
return mi_theap_nonnull_xmalloc_small_zero(theap, size, false, zero, ppage);
}
else {
return mi_theap_malloc_generic(theap, size, zero, huge_alignment, ppage);
}
}
mi_decl_nodiscard static inline mi_decl_restrict void* mi_theap_nonnull_malloc(mi_theap_t* theap, size_t size) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_malloc_zero(theap, size, false, 0, NULL);
}
mi_decl_nodiscard static inline mi_decl_restrict void* mi_theap_nonnull_zalloc(mi_theap_t* theap, size_t size) mi_attr_noexcept {
mi_assert(theap!=NULL);
return mi_theap_nonnull_malloc_zero(theap, size, true, 0, NULL);
}
mi_decl_nodiscard extern inline mi_decl_restrict void* mi_theap_malloc(mi_theap_t* theap, size_t size) mi_attr_noexcept {
return _mi_theap_malloc_zero(theap, size, false, 0, NULL);
}
mi_decl_nodiscard extern inline mi_decl_restrict void* mi_theap_zalloc(mi_theap_t* theap, size_t size) mi_attr_noexcept {
return _mi_theap_malloc_zero(theap, size, true, 0, NULL);
}
mi_decl_nodiscard mi_decl_restrict void* mi_malloc(size_t size) mi_attr_noexcept {
return mi_theap_malloc(_mi_theap_default(), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_zalloc(size_t size) mi_attr_noexcept {
return mi_theap_zalloc(_mi_theap_default(), size);
}
mi_decl_nodiscard static mi_decl_noinline mi_decl_restrict void* mi_heap_init_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept {
return mi_theap_nonnull_malloc(_mi_heap_theap_get_or_init(heap), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_malloc(mi_heap_t* heap, size_t size) mi_attr_noexcept {
mi_theap_t* const theap = _mi_heap_theap_cached(heap);
if mi_likely(theap!=NULL) { return mi_theap_nonnull_malloc(theap, size); }
else { return mi_heap_init_malloc(heap, size); }
}
mi_decl_nodiscard static mi_decl_noinline mi_decl_restrict void* mi_heap_init_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept {
return mi_theap_nonnull_zalloc(_mi_heap_theap_get_or_init(heap), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_zalloc(mi_heap_t* heap, size_t size) mi_attr_noexcept {
mi_theap_t* const theap = _mi_heap_theap_cached(heap);
if mi_likely(theap!=NULL) { return mi_theap_nonnull_zalloc(theap, size); }
else { return mi_heap_init_zalloc(heap, size); }
}
mi_decl_nodiscard extern inline mi_decl_restrict void* mi_theap_calloc(mi_theap_t* theap, size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count,size,&total)) return NULL;
return mi_theap_zalloc(theap,total);
}
mi_decl_nodiscard mi_decl_restrict void* mi_calloc(size_t count, size_t size) mi_attr_noexcept {
return mi_theap_calloc(_mi_theap_default(), count, size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
return mi_theap_calloc(_mi_heap_theap(heap), count, size);
}
static void* mi_ublock_size( void* p, mi_page_t* page, size_t* pblock_size ) {
mi_assert_internal(page == _mi_ptr_page(p));
if (pblock_size!=NULL) {
if (p!=NULL) { *pblock_size = mi_page_block_size(page); }
}
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_umalloc_small(size_t size, size_t* pblock_size) mi_attr_noexcept {
mi_page_t* page;
void* p = mi_theap_xmalloc_small_zero(_mi_theap_default(), size, false, false, &page);
return mi_ublock_size(p,page,pblock_size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_uzalloc_small(size_t size, size_t* pblock_size) mi_attr_noexcept {
mi_page_t* page;
void* p = mi_theap_xmalloc_small_zero(_mi_theap_default(), size, false, true, &page);
return mi_ublock_size(p,page,pblock_size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_umalloc(size_t size, size_t* pblock_size) mi_attr_noexcept {
mi_page_t* page;
void* p = _mi_theap_malloc_zero(_mi_theap_default(), size, false, 0, &page);
return mi_ublock_size(p,page,pblock_size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_uzalloc(size_t size, size_t* pblock_size) mi_attr_noexcept {
mi_page_t* page;
void* p = _mi_theap_malloc_zero(_mi_theap_default(), size, true, 0, &page);
return mi_ublock_size(p,page,pblock_size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_ucalloc(size_t count, size_t size, size_t* pblock_size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count,size,&total)) return NULL;
return mi_uzalloc(total, pblock_size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_mallocn(size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_malloc(total);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_heap_malloc(heap, total);
}
void* mi_expand(void* p, size_t newsize) mi_attr_noexcept {
#if MI_PADDING
MI_UNUSED(p); MI_UNUSED(newsize);
return NULL;
#else
if (p == NULL) return NULL;
const mi_page_t* const page = mi_ptr_page_validate(p,"mi_expand");
const size_t size = _mi_page_usable_size(page,p);
if (newsize > size) return NULL;
return p; #endif
}
static mi_decl_forceinline void* mi_theap_realloc_zero_ex(mi_theap_t* theap, void* p, size_t newsize, bool zero, size_t* pblock_size_pre, size_t* pblock_size_post) mi_attr_noexcept {
const mi_page_t* page;
size_t size;
if (p==NULL) {
page = NULL;
size = 0;
if (pblock_size_pre!=NULL) { *pblock_size_pre = 0; }
}
else {
page = mi_ptr_page_validate(p,"mi_realloc");
if mi_unlikely(page==NULL) { if (pblock_size_pre!=NULL) { *pblock_size_pre = 0; }
if (pblock_size_post!=NULL) { *pblock_size_post = 0; }
return NULL;
}
size = _mi_page_usable_size(page,p);
if (pblock_size_pre!=NULL) { *pblock_size_pre = mi_page_block_size(page); }
}
if mi_unlikely(newsize<=size && newsize>=(size/2) && newsize>0) { mi_assert_internal(page!=NULL); #if MI_THEAP_INITASNULL
if (theap!=NULL)
#endif
{
if (mi_page_heap(page)==_mi_theap_heap_peek(theap)) { mi_assert_internal(p!=NULL);
if (pblock_size_post!=NULL) { *pblock_size_post = mi_page_block_size(page); }
return p; }
}
}
mi_page_t* newpage; void* const newp = _mi_theap_malloc_zero(theap,newsize,false ,0,&newpage);
if mi_likely(newp != NULL) {
if (pblock_size_post!=NULL) { *pblock_size_post = mi_page_block_size(newpage); }
const size_t copy_size = (newsize > size ? size : newsize);
const size_t zero_start = _mi_align_down( (copy_size >= sizeof(intptr_t) ? copy_size - sizeof(intptr_t) : 0), sizeof(intptr_t)); const size_t usable = _mi_page_usable_size(newpage,newp);
mi_assert_internal(usable >= newsize);
if (zero && usable > zero_start) {
_mi_memzero_aligned((uint8_t*)newp + zero_start, usable - zero_start);
}
else if (newsize == 0) {
((uint8_t*)newp)[0] = 0; }
if mi_likely(p != NULL) {
mi_track_mem_defined(p,copy_size); _mi_memcpy_aligned(newp, p, copy_size);
mi_free(p); }
}
return newp;
}
void* _mi_theap_realloc_zero(mi_theap_t* theap, void* p, size_t newsize, bool zero) mi_attr_noexcept {
return mi_theap_realloc_zero_ex(theap,p,newsize,zero,NULL,NULL);
}
mi_decl_nodiscard void* mi_theap_realloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept {
if (p==NULL) {
return mi_theap_malloc(theap,newsize);
}
else {
return _mi_theap_realloc_zero(theap, p, newsize, false);
}
}
mi_decl_nodiscard void* mi_theap_rezalloc(mi_theap_t* theap, void* p, size_t newsize) mi_attr_noexcept {
if (p==NULL) {
return mi_theap_zalloc(theap,newsize);
}
else {
return _mi_theap_realloc_zero(theap, p, newsize, true);
}
}
static void* mi_theap_recalloc(mi_theap_t* theap, void* p, size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_theap_rezalloc(theap, p, total);
}
mi_decl_nodiscard void* mi_realloc(void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_realloc(_mi_theap_default(),p,newsize);
}
mi_decl_nodiscard void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_theap_realloc(_mi_theap_default(),p,total);
}
mi_decl_nodiscard void* mi_urealloc(void* p, size_t newsize, size_t* pblock_size_pre, size_t* pblock_size_post) mi_attr_noexcept {
return mi_theap_realloc_zero_ex(_mi_theap_default(),p,newsize, false, pblock_size_pre, pblock_size_post);
}
static void* mi_theap_reallocf(mi_theap_t* xtheap, void* p, size_t newsize) mi_attr_noexcept {
void* newp = mi_theap_realloc(xtheap, p, newsize);
if (newp==NULL && p!=NULL) mi_free(p);
return newp;
}
mi_decl_nodiscard void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_reallocf(_mi_theap_default(),p,newsize);
}
mi_decl_nodiscard void* mi_rezalloc(void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_rezalloc(_mi_theap_default(), p, newsize);
}
mi_decl_nodiscard void* mi_recalloc(void* p, size_t count, size_t size) mi_attr_noexcept {
return mi_theap_recalloc(_mi_theap_default(), p, count, size);
}
mi_decl_nodiscard void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_realloc(_mi_heap_theap(heap), p, newsize);
}
mi_decl_nodiscard void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
size_t total;
if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_theap_realloc(_mi_heap_theap(heap), p, total);
}
mi_decl_nodiscard void* mi_heap_reallocf(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_reallocf(_mi_heap_theap(heap), p, newsize);
}
mi_decl_nodiscard void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsize) mi_attr_noexcept {
return mi_theap_rezalloc(_mi_heap_theap(heap), p, newsize);
}
mi_decl_nodiscard void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
return mi_theap_recalloc(_mi_heap_theap(heap), p, count, size);
}
mi_decl_nodiscard static mi_decl_restrict char* mi_theap_strdup(mi_theap_t* xtheap, const char* s) mi_attr_noexcept {
if (s == NULL) return NULL;
size_t len = _mi_strlen(s);
if (len > MI_MAX_ALLOC_SIZE - 1) return NULL; char* t = (char*)mi_theap_malloc(xtheap,len+1);
if (t == NULL) return NULL;
_mi_memcpy(t, s, len);
t[len] = 0;
return t;
}
mi_decl_nodiscard mi_decl_restrict char* mi_strdup(const char* s) mi_attr_noexcept {
return mi_theap_strdup(_mi_theap_default(), s);
}
mi_decl_nodiscard mi_decl_restrict char* mi_heap_strdup(mi_heap_t* heap, const char* s) mi_attr_noexcept {
return mi_theap_strdup(_mi_heap_theap(heap), s);
}
mi_decl_nodiscard static mi_decl_restrict char* mi_theap_strndup(mi_theap_t* xtheap, const char* s, size_t n) mi_attr_noexcept {
if (s == NULL) return NULL;
const size_t len = _mi_strnlen(s,n); if (len > MI_MAX_ALLOC_SIZE - 1) return NULL; char* t = (char*)mi_theap_malloc(xtheap, len+1);
if (t == NULL) return NULL;
_mi_memcpy(t, s, len);
t[len] = 0;
return t;
}
mi_decl_nodiscard mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_attr_noexcept {
return mi_theap_strndup(_mi_theap_default(),s,n);
}
mi_decl_nodiscard mi_decl_restrict char* mi_heap_strndup(mi_heap_t* heap, const char* s, size_t n) mi_attr_noexcept {
return mi_theap_strndup(_mi_heap_theap(heap), s, n);
}
#ifndef __wasi__
#ifdef _WIN32
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
mi_decl_nodiscard static mi_decl_restrict char* mi_theap_realpath(mi_theap_t* xtheap, const char* fname, char* resolved_name) mi_attr_noexcept {
if (fname==NULL || *fname==0) {
errno = EINVAL;
return NULL;
}
char buf[PATH_MAX];
DWORD res = GetFullPathNameA(fname, PATH_MAX, (resolved_name == NULL ? buf : resolved_name), NULL);
if (res == 0) {
DWORD err = GetLastError();
switch (err) {
case ERROR_LOCK_VIOLATION:
case ERROR_SHARING_VIOLATION:
case ERROR_INVALID_ACCESS: errno = EACCES; break;
case ERROR_INVALID_HANDLE:
case ERROR_INVALID_FUNCTION: errno = EINVAL; break;
case ERROR_PATH_NOT_FOUND: errno = ENOTDIR; break;
case ERROR_FILE_NOT_FOUND: errno = ENOENT; break;
case ERROR_NOT_ENOUGH_MEMORY: errno = ENOMEM; break;
default: errno = EIO;
}
return NULL;
}
else if (res > PATH_MAX) {
errno = ENAMETOOLONG;
return NULL;
}
else if (resolved_name != NULL) {
return resolved_name;
}
else {
return mi_theap_strndup(xtheap, buf, PATH_MAX);
}
}
#else
#include <unistd.h>
static size_t mi_path_max(void) {
static _Atomic(size_t) path_max = 0;
size_t pmax = mi_atomic_load_acquire(&path_max);
if (pmax == 0) {
long m = 0;
#ifdef _PC_PATH_MAX
m = pathconf("/",_PC_PATH_MAX);
#endif
if (m <= 0) pmax = 4096; else if (m < 256) pmax = 256; else if (m > 64*1024) pmax = 64*1024; else pmax = m;
size_t expected = 0;
mi_atomic_cas_strong_acq_rel(&path_max, &expected, pmax);
}
return pmax;
}
char* mi_theap_realpath(mi_theap_t* xtheap, const char* fname, char* resolved_name) mi_attr_noexcept {
if (resolved_name != NULL) {
return realpath(fname,resolved_name);
}
else {
const size_t n = mi_path_max();
char* const buf = (char*)mi_theap_zalloc(xtheap,n+1);
if (buf == NULL) {
errno = ENOMEM;
return NULL;
}
char* rname = realpath(fname,buf);
char* result = mi_theap_strndup(xtheap,rname,n); mi_free(buf);
return result;
}
}
#endif
mi_decl_nodiscard mi_decl_restrict char* mi_realpath(const char* fname, char* resolved_name) mi_attr_noexcept {
return mi_theap_realpath(_mi_theap_default(),fname,resolved_name);
}
mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
return mi_theap_realpath(_mi_heap_theap(heap), fname, resolved_name);
}
#endif
#define MI_TRY_NEW_MAX (4)
#ifdef __cplusplus
#include <new>
static bool mi_try_new_handler(bool nothrow) {
#if defined(_MSC_VER) || (__cplusplus >= 201103L)
std::new_handler h = std::get_new_handler();
#else
std::new_handler h = std::set_new_handler();
std::set_new_handler(h);
#endif
if (h==NULL) {
_mi_error_message(ENOMEM, "out of memory in 'new'");
#if defined(_CPPUNWIND) || defined(__cpp_exceptions)
if (!nothrow) {
throw std::bad_alloc();
}
#else
MI_UNUSED(nothrow);
#endif
return false;
}
else if (!nothrow) {
h();
return true;
}
else {
try {
h();
}
catch(...) { return false; }
return true;
}
}
#else
typedef void (*std_new_handler_t)(void);
#if (defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)))
std_new_handler_t __attribute__((weak)) _ZSt15get_new_handlerv(void) {
return NULL;
}
static std_new_handler_t mi_get_new_handler(void) {
return _ZSt15get_new_handlerv();
}
#else
static std_new_handler_t mi_get_new_handler(void) {
return NULL;
}
#endif
static bool mi_try_new_handler(bool nothrow) {
std_new_handler_t h = mi_get_new_handler();
if (h==NULL) {
_mi_error_message(ENOMEM, "out of memory in 'new'");
if (!nothrow) {
abort(); }
return false;
}
else {
h();
return true;
}
}
#endif
static mi_decl_noinline void* mi_theap_try_new(mi_theap_t* theap, size_t size, bool nothrow ) {
void* p = NULL;
for(int i = 0; i < MI_TRY_NEW_MAX && p == NULL && mi_try_new_handler(nothrow); i++) {
if (size > MI_MAX_ALLOC_SIZE) return NULL; p = mi_theap_malloc(theap,size);
}
return p;
}
static mi_decl_noinline void* mi_heap_try_new(mi_heap_t* heap, size_t size, bool nothrow) {
return mi_theap_try_new(_mi_heap_theap(heap), size, nothrow);
}
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new(mi_theap_t* theap, size_t size) {
void* p = mi_theap_malloc(theap,size);
if mi_unlikely(p == NULL) return mi_theap_try_new(theap, size, false);
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_new(size_t size) {
return mi_theap_alloc_new(_mi_theap_default(), size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new(mi_heap_t* heap, size_t size) {
void* p = mi_heap_malloc(heap, size);
if mi_unlikely(p == NULL) return mi_heap_try_new(heap, size, false);
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new_n(mi_theap_t* theap, size_t count, size_t size) {
size_t total;
if mi_unlikely(mi_count_size_overflow(count, size, &total)) {
mi_try_new_handler(false); return NULL;
}
else {
return mi_theap_alloc_new(theap,total);
}
}
mi_decl_nodiscard mi_decl_restrict void* mi_new_n(size_t count, size_t size) {
return mi_theap_alloc_new_n(_mi_theap_default(), count, size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_heap_alloc_new_n(mi_heap_t* heap, size_t count, size_t size) {
return mi_theap_alloc_new_n(_mi_heap_theap(heap), count, size);
}
mi_decl_nodiscard mi_decl_restrict void* mi_theap_alloc_new_nothrow(mi_theap_t* theap, size_t size) mi_attr_noexcept {
void* p = mi_theap_malloc(theap,size);
if mi_unlikely(p == NULL) return mi_theap_try_new(theap, size, true);
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_new_nothrow(size_t size) mi_attr_noexcept {
return mi_theap_alloc_new_nothrow(_mi_theap_default(), size);
}
static mi_decl_noinline void* mi_try_new_aligned(size_t size, size_t alignment, bool nothrow) {
void* p = NULL;
for(int i = 0; i < MI_TRY_NEW_MAX && p==NULL && mi_try_new_handler(nothrow); i++) {
if (!mi_alignment_is_valid(alignment)) return NULL;
p = mi_malloc_aligned(size,alignment);
}
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_new_aligned(size_t size, size_t alignment) {
void* p = mi_malloc_aligned(size, alignment);
if mi_unlikely(p==NULL) return mi_try_new_aligned(size,alignment,false);
return p;
}
mi_decl_nodiscard mi_decl_restrict void* mi_new_aligned_nothrow(size_t size, size_t alignment) mi_attr_noexcept {
void* p = mi_malloc_aligned(size, alignment);
if mi_unlikely(p==NULL) return mi_try_new_aligned(size,alignment,true);
return p;
}
static mi_decl_noinline void* mi_try_new_realloc(void* p, size_t newsize) {
void* q = NULL;
for(int i = 0; i < MI_TRY_NEW_MAX && q==NULL && mi_try_new_handler(false); i++) {
if (newsize > MI_MAX_ALLOC_SIZE) return NULL;
q = mi_realloc(p,newsize);
}
return q;
}
mi_decl_nodiscard void* mi_new_realloc(void* p, size_t newsize) {
void* q = mi_realloc(p, newsize);
if (q == NULL) return mi_try_new_realloc(p,newsize);
return q;
}
mi_decl_nodiscard void* mi_new_reallocn(void* p, size_t newcount, size_t size) {
size_t total;
if mi_unlikely(mi_count_size_overflow(newcount, size, &total)) {
mi_try_new_handler(false);
return NULL;
}
else {
return mi_new_realloc(p, total);
}
}
#ifdef __cplusplus
void* _mi_externs[] = {
(void*)&_mi_page_malloc_zero,
(void*)&_mi_theap_malloc_zero,
(void*)&mi_theap_malloc,
(void*)&mi_theap_zalloc,
(void*)&mi_theap_malloc_small,
(void*)&mi_theap_zalloc_small,
(void*)&mi_theap_calloc,
(void*)&mi_malloc,
(void*)&mi_malloc_small,
(void*)&mi_zalloc,
(void*)&mi_zalloc_small,
(void*)&mi_heap_malloc,
(void*)&mi_heap_malloc_small,
(void*)&mi_malloc_aligned
};
#endif