Some runtime systems use deferred free-ing, for example when using reference counting to limit the worst case free time. Such systems can register (re-entrant) deferred free function to free more memory on demand. When the force parameter is true all possible memory should be freed. The per-thread heartbeat parameter is monotonically increasing and guaranteed to be deterministic if the program allocates deterministically. The deferred_free function is guaranteed to be called deterministically after some number of allocations (regardless of freeing or available free memory). At most one deferred_free function can be active.
+
+
+
-
8 #error "documentation file only!" 112 void*
mi_calloc(
size_t count,
size_t size);
138 void*
mi_recalloc(
void* p,
size_t count,
size_t size);
153 void*
mi_expand(
void* p,
size_t newsize);
175 void*
mi_reallocn(
void* p,
size_t count,
size_t size);
229 char*
mi_realpath(
const char* fname,
char* resolved_name);
243 #define MI_SMALL_SIZE_MAX (128*sizeof(void*)) 582 void*
mi_recalloc(
void* p,
size_t newcount,
size_t size) ;
616 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp))) 619 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp))) 622 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp))) 625 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp))) 628 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp))) 631 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp))) 634 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp))) 637 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp))) 640 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp))) 643 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp))) 646 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp))) 685 typedef struct mi_heap_area_s {
724 typedef enum mi_option_e {
764 void*
mi_recalloc(
void* p,
size_t count,
size_t size);
785 void*
mi_new(std::size_t n) noexcept(
false);
788 void*
mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(
false);
void mi_option_enable_default(mi_option_t option, bool enable)
+
8 #error "documentation file only!" 112 void*
mi_calloc(
size_t count,
size_t size);
138 void*
mi_recalloc(
void* p,
size_t count,
size_t size);
153 void*
mi_expand(
void* p,
size_t newsize);
175 void*
mi_reallocn(
void* p,
size_t count,
size_t size);
229 char*
mi_realpath(
const char* fname,
char* resolved_name);
243 #define MI_SMALL_SIZE_MAX (128*sizeof(void*)) 606 void*
mi_recalloc(
void* p,
size_t newcount,
size_t size) ;
640 #define mi_malloc_tp(tp) ((tp*)mi_malloc(sizeof(tp))) 643 #define mi_zalloc_tp(tp) ((tp*)mi_zalloc(sizeof(tp))) 646 #define mi_calloc_tp(tp,count) ((tp*)mi_calloc(count,sizeof(tp))) 649 #define mi_mallocn_tp(tp,count) ((tp*)mi_mallocn(count,sizeof(tp))) 652 #define mi_reallocn_tp(p,tp,count) ((tp*)mi_reallocn(p,count,sizeof(tp))) 655 #define mi_heap_malloc_tp(hp,tp) ((tp*)mi_heap_malloc(hp,sizeof(tp))) 658 #define mi_heap_zalloc_tp(hp,tp) ((tp*)mi_heap_zalloc(hp,sizeof(tp))) 661 #define mi_heap_calloc_tp(hp,tp,count) ((tp*)mi_heap_calloc(hp,count,sizeof(tp))) 664 #define mi_heap_mallocn_tp(hp,tp,count) ((tp*)mi_heap_mallocn(hp,count,sizeof(tp))) 667 #define mi_heap_reallocn_tp(hp,p,tp,count) ((tp*)mi_heap_reallocn(p,count,sizeof(tp))) 670 #define mi_heap_recalloc_tp(hp,p,tp,count) ((tp*)mi_heap_recalloc(p,count,sizeof(tp))) 709 typedef struct mi_heap_area_s {
748 typedef enum mi_option_e {
788 void*
mi_recalloc(
void* p,
size_t count,
size_t size);
809 void*
mi_new(std::size_t n) noexcept(
false);
812 void*
mi_new_n(
size_t count,
size_t size) noexcept(
false);
815 void*
mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(
false);
void mi_option_enable_default(mi_option_t option, bool enable)
size_t mi_usable_size(void *p)
Return the available bytes in a memory block.
void * mi_reallocn(void *p, size_t count, size_t size)
Re-allocate memory to count elements of size bytes.
void * mi_malloc_aligned(size_t size, size_t alignment)
Allocate size bytes aligned by alignment.
@@ -116,16 +116,18 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_stats_merge(void)
Merge thread local statistics with the main statistics and reset.
void mi_option_set_default(mi_option_t option, long value)
void * mi_new_aligned(std::size_t n, std::align_val_t alignment) noexcept(false)
raise std::bad_alloc exception on failure.
+
void() mi_error_fun(int err, void *arg)
Type of error callback functions.
Definition: mimalloc-doc.h:381
void * mi_rezalloc(void *p, size_t newsize)
-
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:730
+
Eagerly commit segments (4MiB) (enabled by default).
Definition: mimalloc-doc.h:754
void * mi_heap_zalloc(mi_heap_t *heap, size_t size)
Allocate zero-initialized in a specific heap.
void mi_option_set(mi_option_t option, long value)
-
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:731
+
Eagerly commit large (256MiB) memory regions (enabled by default, except on Windows)
Definition: mimalloc-doc.h:755
void mi_cfree(void *p)
Just as free but also checks if the pointer p belongs to our heap.
void * mi_recalloc_aligned(void *p, size_t newcount, size_t size, size_t alignment)
-
Definition: mimalloc-doc.h:742
+
Definition: mimalloc-doc.h:766
void * mi_realloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:686
+
void * blocks
start of the area containing heap blocks
Definition: mimalloc-doc.h:710
+
void * mi_new_n(size_t count, size_t size) noexcept(false)
raise std::bad_alloc exception on failure or overflow.
void * mi_realloc_aligned(void *p, size_t newsize, size_t alignment)
int mi__posix_memalign(void **p, size_t alignment, size_t size)
void mi_free(void *p)
Free previously allocated memory.
@@ -141,36 +143,37 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void * mi_heap_rezalloc_aligned_at(mi_heap_t *heap, void *p, size_t newsize, size_t alignment, size_t offset)
void * mi_zalloc(size_t size)
Allocate zero-initialized size bytes.
void * mi_heap_rezalloc(mi_heap_t *heap, void *p, size_t newsize)
-
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:734
+
The number of segments per thread to keep cached.
Definition: mimalloc-doc.h:758
void * mi_heap_calloc(mi_heap_t *heap, size_t count, size_t size)
Allocate count zero-initialized elements in a specific heap.
void * mi_new(std::size_t n) noexcept(false)
raise std::bad_alloc exception on failure.
void * mi_heap_calloc_aligned(mi_heap_t *heap, size_t count, size_t size, size_t alignment)
bool mi_is_redirected()
Is the C runtime malloc API redirected?
-
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:690
+
size_t block_size
size in bytes of one block
Definition: mimalloc-doc.h:714
void * mi_reallocarray(void *p, size_t count, size_t size)
int mi_reserve_huge_os_pages_interleave(size_t pages, size_t numa_nodes, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) evenly divided over numa_nodes nodes, but stops after at most t...
void() mi_deferred_free_fun(bool force, unsigned long long heartbeat, void *arg)
Type of deferred free functions.
Definition: mimalloc-doc.h:342
bool mi_is_in_heap_region(const void *p)
Is a pointer part of our heap?
void mi_option_enable(mi_option_t option, bool enable)
void * mi_realloc(void *p, size_t newsize)
Re-allocate memory to newsize bytes.
-
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:733
+
The number of huge OS pages (1GiB in size) to reserve at the start of the program.
Definition: mimalloc-doc.h:757
void * mi_heap_reallocf(mi_heap_t *heap, void *p, size_t newsize)
void mi_free_size_aligned(void *p, size_t size, size_t alignment)
void * mi_rezalloc_aligned_at(void *p, size_t newsize, size_t alignment, size_t offset)
-
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:735
+
Reset page memory after mi_option_reset_delay milliseconds when it becomes free.
Definition: mimalloc-doc.h:759
void mi_thread_done(void)
Uninitialize mimalloc on a thread.
bool mi_heap_visit_blocks(const mi_heap_t *heap, bool visit_all_blocks, mi_block_visit_fun *visitor, void *arg)
Visit all areas and blocks in a heap.
-
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:738
+
Pretend there are at most N NUMA nodes.
Definition: mimalloc-doc.h:762
void * mi_malloc(size_t size)
Allocate size bytes.
bool mi_option_enabled(mi_option_t option)
-
Experimental.
Definition: mimalloc-doc.h:739
+
void mi_register_error(mi_error_fun *errfun, void *arg)
Register an error callback function.
+
Experimental.
Definition: mimalloc-doc.h:763
char * mi_heap_strndup(mi_heap_t *heap, const char *s, size_t n)
Duplicate a string of at most length n in a specific heap.
-
bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
Visitor function passed to mi_heap_visit_blocks()
Definition: mimalloc-doc.h:700
+
bool() mi_block_visit_fun(const mi_heap_t *heap, const mi_heap_area_t *area, void *block, size_t block_size, void *arg)
Visitor function passed to mi_heap_visit_blocks()
Definition: mimalloc-doc.h:724
void * mi_heap_recalloc(mi_heap_t *heap, void *p, size_t newcount, size_t size)
void * mi_heap_malloc_aligned_at(mi_heap_t *heap, size_t size, size_t alignment, size_t offset)
char * mi_realpath(const char *fname, char *resolved_name)
Resolve a file path name.
-
Print error messages to stderr.
Definition: mimalloc-doc.h:727
-
Experimental.
Definition: mimalloc-doc.h:736
+
Print error messages to stderr.
Definition: mimalloc-doc.h:751
+
Experimental.
Definition: mimalloc-doc.h:760
void * mi_heap_rezalloc_aligned(mi_heap_t *heap, void *p, size_t newsize, size_t alignment)
void * mi_memalign(size_t alignment, size_t size)
void * mi_new_aligned_nothrow(size_t n, size_t alignment)
return NULL on failure.
@@ -179,11 +182,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
bool mi_heap_contains_block(mi_heap_t *heap, const void *p)
Does a heap contain a pointer to a previously allocated block?
void mi_heap_collect(mi_heap_t *heap, bool force)
Release outstanding resources in a specific heap.
void * mi_heap_recalloc_aligned_at(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment, size_t offset)
-
Print verbose messages to stderr.
Definition: mimalloc-doc.h:728
+
Print verbose messages to stderr.
Definition: mimalloc-doc.h:752
void * mi_zalloc_aligned_at(size_t size, size_t alignment, size_t offset)
void * mi_malloc_aligned_at(size_t size, size_t alignment, size_t offset)
Allocate size bytes aligned by alignment at a specified offset.
void mi_heap_delete(mi_heap_t *heap)
Delete a previously allocated heap.
-
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:741
+
OS tag to assign to mimalloc'd memory.
Definition: mimalloc-doc.h:765
mi_heap_t * mi_heap_get_default()
Get the default heap that is used for mi_malloc() et al.
int mi_reserve_huge_os_pages_at(size_t pages, int numa_node, size_t timeout_msecs)
Reserve pages of huge OS pages (1GiB) at a specific numa_node, but stops after at most timeout_msecs ...
void * mi_aligned_alloc(size_t alignment, size_t size)
@@ -191,22 +194,22 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
void mi_thread_init(void)
Initialize mimalloc on a thread.
size_t mi_good_size(size_t size)
Return the used allocation size.
void mi_stats_print(void *out)
Print the main statistics.
-
Experimental.
Definition: mimalloc-doc.h:740
+
Experimental.
Definition: mimalloc-doc.h:764
void * mi_heap_recalloc_aligned(mi_heap_t *heap, void *p, size_t newcount, size_t size, size_t alignment)
void * mi_heap_mallocn(mi_heap_t *heap, size_t count, size_t size)
Allocate count elements in a specific heap.
-
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:685
+
An area of heap space contains blocks of a single size.
Definition: mimalloc-doc.h:709
void mi_thread_stats_print_out(mi_output_fun *out, void *arg)
Print out heap statistics for this thread.
-
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:726
+
Print statistics to stderr when the program is done.
Definition: mimalloc-doc.h:750
void * mi_zalloc_aligned(size_t size, size_t alignment)
-
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:687
-
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:481
-
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:689
+
size_t reserved
bytes reserved for this area
Definition: mimalloc-doc.h:711
+
struct mi_heap_s mi_heap_t
Type of first-class heaps.
Definition: mimalloc-doc.h:505
+
size_t used
bytes in use by allocated blocks
Definition: mimalloc-doc.h:713
void mi_register_deferred_free(mi_deferred_free_fun *deferred_free, void *arg)
Register a deferred free function.
void mi_free_size(void *p, size_t size)
void mi_collect(bool force)
Eagerly free memory.
void mi_heap_destroy(mi_heap_t *heap)
Destroy a heap, freeing all its still allocated blocks.
void * mi_calloc_aligned_at(size_t count, size_t size, size_t alignment, size_t offset)
-
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:732
+
Use large OS pages (2MiB in size) if possible.
Definition: mimalloc-doc.h:756
void * mi_heap_reallocn(mi_heap_t *heap, void *p, size_t count, size_t size)
void mi_register_output(mi_output_fun *out, void *arg)
Register an output function.
void * mi_heap_malloc_small(mi_heap_t *heap, size_t size)
Allocate a small object in a specific heap.
@@ -224,11 +227,11 @@ $(document).ready(function(){initNavTree('mimalloc-doc_8h_source.html','');});
long mi_option_get(mi_option_t option)
mi_heap_t * mi_heap_get_backing()
Get the backing heap.
void mi_free_aligned(void *p, size_t alignment)
-
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:737
+
Delay in milli-seconds before resetting a page (100ms by default)
Definition: mimalloc-doc.h:761
mi_heap_t * mi_heap_new()
Create a new heap that can be used for allocation.
void * mi_heap_malloc(mi_heap_t *heap, size_t size)
Allocate in a specific heap.
-
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:688
-
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:724
+
size_t committed
current committed bytes of this area
Definition: mimalloc-doc.h:712
+
mi_option_t
Runtime options.
Definition: mimalloc-doc.h:748
bool mi_heap_check_owned(mi_heap_t *heap, const void *p)
Check safely if any pointer is part of a heap.
mi_heap_t * mi_heap_set_default(mi_heap_t *heap)
Set the default heap to use for mi_malloc() et al.
diff --git a/docs/navtreeindex0.js b/docs/navtreeindex0.js
index d1b0e072..e2667728 100644
--- a/docs/navtreeindex0.js
+++ b/docs/navtreeindex0.js
@@ -29,27 +29,29 @@ var NAVTREEINDEX0 =
"group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65":[5,6,1],
"group__analysis.html#structmi__heap__area__t":[5,6,0],
"group__extended.html":[5,1],
-"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,19],
-"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,16],
+"group__extended.html#ga089c859d9eddc5f9b4bd946cd53cebee":[5,1,21],
+"group__extended.html#ga0ae4581e85453456a0d658b2b98bf7bf":[5,1,18],
"group__extended.html#ga1ea64283508718d9d645c38efc2f4305":[5,1,0],
-"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,20],
-"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,14],
+"group__extended.html#ga220f29f40a44404b0061c15bc1c31152":[5,1,22],
+"group__extended.html#ga251d369cda3f1c2a955c555486ed90e5":[5,1,2],
+"group__extended.html#ga256cc6f13a142deabbadd954a217e228":[5,1,16],
"group__extended.html#ga299dae78d25ce112e384a98b7309c5be":[5,1,1],
-"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,13],
-"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,11],
-"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,8],
-"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,15],
-"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,3],
-"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,5],
-"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,7],
-"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,10],
-"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,12],
-"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,6],
-"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,18],
-"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,4],
-"group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,2],
-"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,9],
-"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,17],
+"group__extended.html#ga2d126e5c62d3badc35445e5d84166df2":[5,1,15],
+"group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50":[5,1,13],
+"group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece":[5,1,9],
+"group__extended.html#ga3bb8468b8cfcc6e2a61d98aee85c5f99":[5,1,17],
+"group__extended.html#ga421430e2226d7d468529cec457396756":[5,1,4],
+"group__extended.html#ga5f071b10d4df1c3658e04e7fd67a94e6":[5,1,6],
+"group__extended.html#ga7136c2e55cb22c98ecf95d08d6debb99":[5,1,8],
+"group__extended.html#ga7795a13d20087447281858d2c771cca1":[5,1,12],
+"group__extended.html#ga854b1de8cb067c7316286c28b2fcd3d1":[5,1,14],
+"group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45":[5,1,10],
+"group__extended.html#gaad25050b19f30cd79397b227e0157a3f":[5,1,7],
+"group__extended.html#gab1dac8476c46cb9eecab767eb40c1525":[5,1,20],
+"group__extended.html#gac057927cd06c854b45fe7847e921bd47":[5,1,5],
+"group__extended.html#gad823d23444a4b77a40f66bf075a98a0c":[5,1,3],
+"group__extended.html#gae5b17ff027cd2150b43a33040250cf3f":[5,1,11],
+"group__extended.html#gaf8e73efc2cbca9ebfdfb166983a04c17":[5,1,19],
"group__heap.html":[5,3],
"group__heap.html#ga00e95ba1e01acac3cfd95bb7a357a6f0":[5,3,20],
"group__heap.html#ga08ca6419a5c057a4d965868998eef487":[5,3,3],
@@ -121,18 +123,19 @@ var NAVTREEINDEX0 =
"group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9":[5,8,3],
"group__posix.html#ga1326d2e4388630b5f81ca7206318b8e5":[5,8,1],
"group__posix.html#ga4531c9e775bb3ae12db57c1ba8a5d7de":[5,8,6],
-"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,15],
+"group__posix.html#ga48fad8648a2f1dab9c87ea9448a52088":[5,8,16],
"group__posix.html#ga705dc7a64bffacfeeb0141501a5c35d7":[5,8,2],
"group__posix.html#ga72e9d7ffb5fe94d69bc722c8506e27bc":[5,8,5],
-"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,16],
+"group__posix.html#ga73baaf5951f5165ba0763d0c06b6a93b":[5,8,17],
"group__posix.html#gaab7fa71ea93b96873f5d9883db57d40e":[5,8,8],
"group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545":[5,8,9],
"group__posix.html#gab5e29558926d934c3f1cae8c815f942c":[5,8,11],
-"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[5,8,13],
+"group__posix.html#gacff84f226ba9feb2031b8992e5579447":[5,8,14],
"group__posix.html#gad5a69c8fea96aa2b7a7c818c2130090a":[5,8,0],
"group__posix.html#gae01389eedab8d67341ff52e2aad80ebb":[5,8,4],
-"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,8,12],
-"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,14],
+"group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81":[5,8,12],
+"group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a":[5,8,13],
+"group__posix.html#gaeb325c39b887d3b90d85d1eb1712fb1e":[5,8,15],
"group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3":[5,8,10],
"group__typed.html":[5,5],
"group__typed.html#ga0619a62c5fd886f1016030abe91f0557":[5,5,7],
diff --git a/docs/search/all_6.js b/docs/search/all_6.js
index cc7a26ec..7af11c0f 100644
--- a/docs/search/all_6.js
+++ b/docs/search/all_6.js
@@ -11,6 +11,7 @@ var searchData=
['mi_5fcheck_5fowned',['mi_check_owned',['../group__analysis.html#ga628c237489c2679af84a4d0d143b3dd5',1,'mimalloc-doc.h']]],
['mi_5fcollect',['mi_collect',['../group__extended.html#ga421430e2226d7d468529cec457396756',1,'mimalloc-doc.h']]],
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
+ ['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]],
['mi_5fexpand',['mi_expand',['../group__malloc.html#gaaee66a1d483c3e28f585525fb96707e4',1,'mimalloc-doc.h']]],
['mi_5ffree',['mi_free',['../group__malloc.html#gaf2c7b89c327d1f60f59e68b9ea644d95',1,'mimalloc-doc.h']]],
['mi_5ffree_5faligned',['mi_free_aligned',['../group__posix.html#ga0d28d5cf61e6bfbb18c63092939fe5c9',1,'mimalloc-doc.h']]],
@@ -75,6 +76,7 @@ var searchData=
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
+ ['mi_5fnew_5fn',['mi_new_n',['../group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
['mi_5foption_5feager_5fcommit',['mi_option_eager_commit',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca1e8de72c93da7ff22d91e1e27b52ac2b',1,'mimalloc-doc.h']]],
['mi_5foption_5feager_5fcommit_5fdelay',['mi_option_eager_commit_delay',['../group__options.html#ggafebf7ed116adb38ae5218bc3ce06884ca17a190c25be381142d87e0468c4c068c',1,'mimalloc-doc.h']]],
@@ -113,6 +115,7 @@ var searchData=
['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]],
['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]],
['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
+ ['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]],
diff --git a/docs/search/functions_0.js b/docs/search/functions_0.js
index d1d209a1..098041bb 100644
--- a/docs/search/functions_0.js
+++ b/docs/search/functions_0.js
@@ -62,6 +62,7 @@ var searchData=
['mi_5fnew',['mi_new',['../group__posix.html#gaad048a9fce3d02c5909cd05c6ec24545',1,'mimalloc-doc.h']]],
['mi_5fnew_5faligned',['mi_new_aligned',['../group__posix.html#gaef2c2bdb4f70857902d3c8903ac095f3',1,'mimalloc-doc.h']]],
['mi_5fnew_5faligned_5fnothrow',['mi_new_aligned_nothrow',['../group__posix.html#gab5e29558926d934c3f1cae8c815f942c',1,'mimalloc-doc.h']]],
+ ['mi_5fnew_5fn',['mi_new_n',['../group__posix.html#gae7bc4f56cd57ed3359060ff4f38bda81',1,'mimalloc-doc.h']]],
['mi_5fnew_5fnothrow',['mi_new_nothrow',['../group__posix.html#gaeaded64eda71ed6b1d569d3e723abc4a',1,'mimalloc-doc.h']]],
['mi_5foption_5fenable',['mi_option_enable',['../group__options.html#ga6d45a20a3131f18bc351b69763b38ce4',1,'mimalloc-doc.h']]],
['mi_5foption_5fenable_5fdefault',['mi_option_enable_default',['../group__options.html#ga37988264b915a7db92530cc02d5494cb',1,'mimalloc-doc.h']]],
@@ -82,6 +83,7 @@ var searchData=
['mi_5frecalloc_5faligned',['mi_recalloc_aligned',['../group__zeroinit.html#ga3e7e5c291acf1c7fd7ffd9914a9f945f',1,'mimalloc-doc.h']]],
['mi_5frecalloc_5faligned_5fat',['mi_recalloc_aligned_at',['../group__zeroinit.html#ga4ff5e92ad73585418a072c9d059e5cf9',1,'mimalloc-doc.h']]],
['mi_5fregister_5fdeferred_5ffree',['mi_register_deferred_free',['../group__extended.html#ga3460a6ca91af97be4058f523d3cb8ece',1,'mimalloc-doc.h']]],
+ ['mi_5fregister_5ferror',['mi_register_error',['../group__extended.html#gaa1d55e0e894be240827e5d87ec3a1f45',1,'mimalloc-doc.h']]],
['mi_5fregister_5foutput',['mi_register_output',['../group__extended.html#gae5b17ff027cd2150b43a33040250cf3f',1,'mimalloc-doc.h']]],
['mi_5freserve_5fhuge_5fos_5fpages_5fat',['mi_reserve_huge_os_pages_at',['../group__extended.html#ga7795a13d20087447281858d2c771cca1',1,'mimalloc-doc.h']]],
['mi_5freserve_5fhuge_5fos_5fpages_5finterleave',['mi_reserve_huge_os_pages_interleave',['../group__extended.html#ga3132f521fb756fc0e8ec0b74fb58df50',1,'mimalloc-doc.h']]],
diff --git a/docs/search/typedefs_0.js b/docs/search/typedefs_0.js
index 17816828..44a0a6c6 100644
--- a/docs/search/typedefs_0.js
+++ b/docs/search/typedefs_0.js
@@ -2,6 +2,7 @@ var searchData=
[
['mi_5fblock_5fvisit_5ffun',['mi_block_visit_fun',['../group__analysis.html#gadfa01e2900f0e5d515ad5506b26f6d65',1,'mimalloc-doc.h']]],
['mi_5fdeferred_5ffree_5ffun',['mi_deferred_free_fun',['../group__extended.html#ga299dae78d25ce112e384a98b7309c5be',1,'mimalloc-doc.h']]],
+ ['mi_5ferror_5ffun',['mi_error_fun',['../group__extended.html#ga251d369cda3f1c2a955c555486ed90e5',1,'mimalloc-doc.h']]],
['mi_5fheap_5ft',['mi_heap_t',['../group__heap.html#ga34a47cde5a5b38c29f1aa3c5e76943c2',1,'mimalloc-doc.h']]],
['mi_5foutput_5ffun',['mi_output_fun',['../group__extended.html#gad823d23444a4b77a40f66bf075a98a0c',1,'mimalloc-doc.h']]]
];
diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h
index f039fc50..eaa327be 100644
--- a/include/mimalloc-internal.h
+++ b/include/mimalloc-internal.h
@@ -23,25 +23,21 @@ terms of the MIT license. A copy of the license can be found in the file
#if defined(_MSC_VER)
#pragma warning(disable:4127) // constant conditional due to MI_SECURE paths
#define mi_decl_noinline __declspec(noinline)
-#define mi_attr_noreturn
#elif defined(__GNUC__) || defined(__clang__)
#define mi_decl_noinline __attribute__((noinline))
-#define mi_attr_noreturn __attribute__((noreturn))
#else
#define mi_decl_noinline
-#define mi_attr_noreturn
#endif
// "options.c"
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
void _mi_fprintf(mi_output_fun* out, void* arg, const char* fmt, ...);
-void _mi_error_message(const char* fmt, ...);
void _mi_warning_message(const char* fmt, ...);
void _mi_verbose_message(const char* fmt, ...);
void _mi_trace_message(const char* fmt, ...);
void _mi_options_init(void);
-void _mi_fatal_error(const char* fmt, ...) mi_attr_noreturn;
+void _mi_error_message(int err, const char* fmt, ...);
// random.c
void _mi_random_init(mi_random_ctx_t* ctx);
@@ -146,6 +142,29 @@ bool _mi_page_is_valid(mi_page_t* page);
#endif
+/* -----------------------------------------------------------
+ Error codes passed to `_mi_fatal_error`
+ All are recoverable but EFAULT is a serious error and aborts by default in secure mode.
+ For portability define undefined error codes using common Unix codes:
+
+----------------------------------------------------------- */
+#include
+#ifndef EAGAIN // double free
+#define EAGAIN (11)
+#endif
+#ifndef ENOMEM // out of memory
+#define ENOMEM (12)
+#endif
+#ifndef EFAULT // corrupted free-list or meta-data
+#define EFAULT (14)
+#endif
+#ifndef EINVAL // trying to free an invalid pointer
+#define EINVAL (22)
+#endif
+#ifndef EOVERFLOW // count*size overflow
+#define EOVERFLOW (75)
+#endif
+
/* -----------------------------------------------------------
Inlined definitions
@@ -166,30 +185,6 @@ bool _mi_page_is_valid(mi_page_t* page);
#define MI_INIT256(x) MI_INIT128(x),MI_INIT128(x)
-// Overflow detecting multiply
-static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) {
- // quick check for the case where count is one (common for C++ allocators)
- if (count==1) {
- *total = size;
- return false;
- }
-#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
-#include // UINT_MAX, ULONG_MAX
-#if (SIZE_MAX == UINT_MAX)
- return __builtin_umul_overflow(count, size, total);
-#elif (SIZE_MAX == ULONG_MAX)
- return __builtin_umull_overflow(count, size, total);
-#else
- return __builtin_umulll_overflow(count, size, total);
-#endif
-#else /* __builtin_umul_overflow is unavailable */
- #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX)
- *total = count * size;
- return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
- && size > 0 && (SIZE_MAX / size) < count);
-#endif
-}
-
// Is `x` a power of two? (0 is considered a power of two)
static inline bool _mi_is_power_of_two(uintptr_t x) {
return ((x & (x - 1)) == 0);
@@ -229,6 +224,40 @@ static inline size_t _mi_wsize_from_size(size_t size) {
}
+// Overflow detecting multiply
+static inline bool mi_mul_overflow(size_t count, size_t size, size_t* total) {
+#if __has_builtin(__builtin_umul_overflow) || __GNUC__ >= 5
+#include // UINT_MAX, ULONG_MAX
+#if (SIZE_MAX == UINT_MAX)
+ return __builtin_umul_overflow(count, size, total);
+#elif (SIZE_MAX == ULONG_MAX)
+ return __builtin_umull_overflow(count, size, total);
+#else
+ return __builtin_umulll_overflow(count, size, total);
+#endif
+#else /* __builtin_umul_overflow is unavailable */
+ #define MI_MUL_NO_OVERFLOW ((size_t)1 << (4*sizeof(size_t))) // sqrt(SIZE_MAX)
+ *total = count * size;
+ return ((size >= MI_MUL_NO_OVERFLOW || count >= MI_MUL_NO_OVERFLOW)
+ && size > 0 && (SIZE_MAX / size) < count);
+#endif
+}
+
+// Safe multiply `count*size` into `total`; return `true` on overflow.
+static inline bool mi_count_size_overflow(size_t count, size_t size, size_t* total) {
+ if (count==1) { // quick check for the case where count is one (common for C++ allocators)
+ *total = size;
+ return false;
+ }
+ else if (mi_unlikely(mi_mul_overflow(count, size, total))) {
+ _mi_error_message(EOVERFLOW, "allocation request too large (%zu * %zu bytes)\n", count, size);
+ *total = SIZE_MAX;
+ return true;
+ }
+ else return false;
+}
+
+
/* -----------------------------------------------------------
The thread local default heap
----------------------------------------------------------- */
@@ -506,7 +535,7 @@ static inline mi_block_t* mi_block_next(const mi_page_t* page, const mi_block_t*
// check for free list corruption: is `next` at least in the same page?
// TODO: check if `next` is `page->block_size` aligned?
if (mi_unlikely(next!=NULL && !mi_is_in_same_page(block, next))) {
- _mi_fatal_error("corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
+ _mi_error_message(EFAULT, "corrupted free list entry of size %zub at %p: value 0x%zx\n", mi_page_block_size(page), block, (uintptr_t)next);
next = NULL;
}
return next;
diff --git a/include/mimalloc.h b/include/mimalloc.h
index 67ff1a35..1250314c 100644
--- a/include/mimalloc.h
+++ b/include/mimalloc.h
@@ -104,16 +104,23 @@ mi_decl_export mi_decl_allocator void* mi_mallocn(size_t count, size_t size)
mi_decl_export mi_decl_allocator void* mi_reallocn(void* p, size_t count, size_t size) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size2(2,3);
mi_decl_export mi_decl_allocator void* mi_reallocf(void* p, size_t newsize) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
-
mi_decl_export size_t mi_usable_size(const void* p) mi_attr_noexcept;
mi_decl_export size_t mi_good_size(size_t size) mi_attr_noexcept;
+
+// ------------------------------------------------------
+// Internals
+// ------------------------------------------------------
+
typedef void (mi_cdecl mi_deferred_free_fun)(bool force, unsigned long long heartbeat, void* arg);
mi_decl_export void mi_register_deferred_free(mi_deferred_free_fun* deferred_free, void* arg) mi_attr_noexcept;
typedef void (mi_cdecl mi_output_fun)(const char* msg, void* arg);
mi_decl_export void mi_register_output(mi_output_fun* out, void* arg) mi_attr_noexcept;
+typedef void (mi_cdecl mi_error_fun)(int err, void* arg);
+mi_decl_export void mi_register_error(mi_error_fun* fun, void* arg);
+
mi_decl_export void mi_collect(bool force) mi_attr_noexcept;
mi_decl_export int mi_version(void) mi_attr_noexcept;
mi_decl_export void mi_stats_reset(void) mi_attr_noexcept;
@@ -143,9 +150,9 @@ mi_decl_export mi_decl_allocator void* mi_realloc_aligned(void* p, size_t newsiz
mi_decl_export mi_decl_allocator void* mi_realloc_aligned_at(void* p, size_t newsize, size_t alignment, size_t offset) mi_attr_noexcept mi_attr_malloc mi_attr_alloc_size(2);
-// ------------------------------------------------------
-// Heaps
-// ------------------------------------------------------
+// -------------------------------------------------------------------------------------
+// Heaps: first-class, but can only allocate from the same thread that created it.
+// -------------------------------------------------------------------------------------
struct mi_heap_s;
typedef struct mi_heap_s mi_heap_t;
diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c
index 5a59a63a..55b0e041 100644
--- a/src/alloc-aligned.c
+++ b/src/alloc-aligned.c
@@ -79,7 +79,7 @@ mi_decl_allocator void* mi_heap_zalloc_aligned(mi_heap_t* heap, size_t size, siz
mi_decl_allocator void* mi_heap_calloc_aligned_at(mi_heap_t* heap, size_t count, size_t size, size_t alignment, size_t offset) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(count, size, &total)) return NULL;
+ if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_heap_zalloc_aligned_at(heap, total, alignment, offset);
}
@@ -168,13 +168,13 @@ mi_decl_allocator void* mi_heap_rezalloc_aligned(mi_heap_t* heap, void* p, size_
mi_decl_allocator void* mi_heap_recalloc_aligned_at(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment, size_t offset) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(newcount, size, &total)) return NULL;
+ if (mi_count_size_overflow(newcount, size, &total)) return NULL;
return mi_heap_rezalloc_aligned_at(heap, p, total, alignment, offset);
}
mi_decl_allocator void* mi_heap_recalloc_aligned(mi_heap_t* heap, void* p, size_t newcount, size_t size, size_t alignment) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(newcount, size, &total)) return NULL;
+ if (mi_count_size_overflow(newcount, size, &total)) return NULL;
return mi_heap_rezalloc_aligned(heap, p, total, alignment);
}
diff --git a/src/alloc.c b/src/alloc.c
index 37d43d9f..e605c017 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -146,7 +146,7 @@ static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, con
mi_list_contains(page, page->local_free, block) ||
mi_list_contains(page, mi_page_thread_free(page), block))
{
- _mi_fatal_error("double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
+ _mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
return true;
}
return false;
@@ -300,7 +300,7 @@ void mi_free(void* p) mi_attr_noexcept
{
#if (MI_DEBUG>0)
if (mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0)) {
- _mi_error_message("trying to free an invalid (unaligned) pointer: %p\n", p);
+ _mi_error_message(EINVAL, "trying to free an invalid (unaligned) pointer: %p\n", p);
return;
}
#endif
@@ -310,16 +310,16 @@ void mi_free(void* p) mi_attr_noexcept
#if (MI_DEBUG!=0)
if (mi_unlikely(!mi_is_in_heap_region(p))) {
- _mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: 0x%p\n"
+ _mi_warning_message("possibly trying to free a pointer that does not point to a valid heap region: %p\n"
"(this may still be a valid very large allocation (over 64MiB))\n", p);
if (mi_likely(_mi_ptr_cookie(segment) == segment->cookie)) {
- _mi_warning_message("(yes, the previous pointer 0x%p was valid after all)\n", p);
+ _mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p);
}
}
#endif
#if (MI_DEBUG!=0 || MI_SECURE>=4)
if (mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie)) {
- _mi_error_message("trying to free a pointer that does not point to a valid heap space: %p\n", p);
+ _mi_error_message(EINVAL, "trying to free a pointer that does not point to a valid heap space: %p\n", p);
return;
}
#endif
@@ -432,7 +432,7 @@ void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept {
extern inline mi_decl_allocator void* mi_heap_calloc(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(count,size,&total)) return NULL;
+ if (mi_count_size_overflow(count,size,&total)) return NULL;
return mi_heap_zalloc(heap,total);
}
@@ -443,7 +443,7 @@ mi_decl_allocator void* mi_calloc(size_t count, size_t size) mi_attr_noexcept {
// Uninitialized `calloc`
extern mi_decl_allocator void* mi_heap_mallocn(mi_heap_t* heap, size_t count, size_t size) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(count, size, &total)) return NULL;
+ if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_heap_malloc(heap, total);
}
@@ -484,7 +484,7 @@ mi_decl_allocator void* mi_heap_realloc(mi_heap_t* heap, void* p, size_t newsize
mi_decl_allocator void* mi_heap_reallocn(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(count, size, &total)) return NULL;
+ if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_heap_realloc(heap, p, total);
}
@@ -502,7 +502,7 @@ mi_decl_allocator void* mi_heap_rezalloc(mi_heap_t* heap, void* p, size_t newsiz
mi_decl_allocator void* mi_heap_recalloc(mi_heap_t* heap, void* p, size_t count, size_t size) mi_attr_noexcept {
size_t total;
- if (mi_mul_overflow(count, size, &total)) return NULL;
+ if (mi_count_size_overflow(count, size, &total)) return NULL;
return mi_heap_rezalloc(heap, p, total);
}
@@ -570,7 +570,6 @@ char* mi_strndup(const char* s, size_t n) mi_attr_noexcept {
#define PATH_MAX MAX_PATH
#endif
#include
-#include
char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
// todo: use GetFullPathNameW to allow longer file names
char buf[PATH_MAX];
@@ -645,10 +644,6 @@ static bool mi_try_new_handler(bool nothrow) {
}
}
#else
-#include
-#ifndef ENOMEM
-#define ENOMEM 12
-#endif
typedef void (*std_new_handler_t)();
#if (defined(__GNUC__) || defined(__clang__))
@@ -668,7 +663,7 @@ std_new_handler_t mi_get_new_handler() {
static bool mi_try_new_handler(bool nothrow) {
std_new_handler_t h = mi_get_new_handler();
if (h==NULL) {
- if (!nothrow) exit(ENOMEM);
+ if (!nothrow) exit(ENOMEM); // cannot throw in plain C, use exit as we are out of memory anyway.
return false;
}
else {
@@ -718,7 +713,7 @@ void* mi_new_aligned_nothrow(size_t size, size_t alignment) {
void* mi_new_n(size_t count, size_t size) {
size_t total;
- if (mi_unlikely(mi_mul_overflow(count, size, &total))) {
+ if (mi_unlikely(mi_count_size_overflow(count, size, &total))) {
mi_try_new_handler(false); // on overflow we invoke the try_new_handler once to potentially throw std::bad_alloc
return NULL;
}
diff --git a/src/arena.c b/src/arena.c
index 7f1a1caf..f20a03e9 100644
--- a/src/arena.c
+++ b/src/arena.c
@@ -229,18 +229,18 @@ void _mi_arena_free(void* p, size_t size, size_t memid, mi_stats_t* stats) {
mi_arena_t* arena = (mi_arena_t*)mi_atomic_read_ptr_relaxed(mi_atomic_cast(void*, &mi_arenas[arena_idx]));
mi_assert_internal(arena != NULL);
if (arena == NULL) {
- _mi_fatal_error("trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
+ _mi_error_message(EINVAL, "trying to free from non-existent arena: %p, size %zu, memid: 0x%zx\n", p, size, memid);
return;
}
mi_assert_internal(arena->field_count > mi_bitmap_index_field(bitmap_idx));
if (arena->field_count <= mi_bitmap_index_field(bitmap_idx)) {
- _mi_fatal_error("trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
+ _mi_error_message(EINVAL, "trying to free from non-existent arena block: %p, size %zu, memid: 0x%zx\n", p, size, memid);
return;
}
const size_t blocks = mi_block_count_of_size(size);
bool ones = mi_bitmap_unclaim(arena->blocks_inuse, arena->field_count, blocks, bitmap_idx);
if (!ones) {
- _mi_fatal_error("trying to free an already freed block: %p, size %zu\n", p, size);
+ _mi_error_message(EAGAIN, "trying to free an already freed block: %p, size %zu\n", p, size);
return;
};
}
diff --git a/src/init.c b/src/init.c
index b8422c2f..18a18f60 100644
--- a/src/init.c
+++ b/src/init.c
@@ -157,7 +157,7 @@ static bool _mi_heap_init(void) {
// use `_mi_os_alloc` to allocate directly from the OS
mi_thread_data_t* td = (mi_thread_data_t*)_mi_os_alloc(sizeof(mi_thread_data_t),&_mi_stats_main); // Todo: more efficient allocation?
if (td == NULL) {
- _mi_error_message("failed to allocate thread local heap memory\n");
+ _mi_error_message(ENOMEM, "failed to allocate thread local heap memory\n");
return false;
}
mi_tld_t* tld = &td->tld;
diff --git a/src/options.c b/src/options.c
index c12c77e0..b06cbdb4 100644
--- a/src/options.c
+++ b/src/options.c
@@ -287,14 +287,10 @@ void _mi_verbose_message(const char* fmt, ...) {
va_end(args);
}
-void _mi_error_message(const char* fmt, ...) {
+static void mi_show_error_message(const char* fmt, va_list args) {
if (!mi_option_is_enabled(mi_option_show_errors) && !mi_option_is_enabled(mi_option_verbose)) return;
if (mi_atomic_increment(&error_count) > mi_max_error_count) return;
- va_list args;
- va_start(args,fmt);
- mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args);
- va_end(args);
- mi_assert(false);
+ mi_vfprintf(NULL, NULL, "mimalloc: error: ", fmt, args);
}
void _mi_warning_message(const char* fmt, ...) {
@@ -314,14 +310,40 @@ void _mi_assert_fail(const char* assertion, const char* fname, unsigned line, co
}
#endif
-mi_attr_noreturn void _mi_fatal_error(const char* fmt, ...) {
+// --------------------------------------------------------
+// Errors
+// --------------------------------------------------------
+
+static mi_error_fun* volatile mi_error_handler; // = NULL
+static volatile _Atomic(void*) mi_error_arg; // = NULL
+
+static void mi_error_default(int err) {
+ UNUSED(err);
+#if (MI_SECURE>0)
+ if (err==EFAULT) { // abort on serious errors in secure mode (corrupted meta-data)
+ abort();
+ }
+#endif
+}
+
+void mi_register_error(mi_error_fun* fun, void* arg) {
+ mi_error_handler = fun; // can be NULL
+ mi_atomic_write_ptr(&mi_error_arg, arg);
+}
+
+void _mi_error_message(int err, const char* fmt, ...) {
+ // show detailed error message
va_list args;
va_start(args, fmt);
- mi_vfprintf(NULL, NULL, "mimalloc: fatal: ", fmt, args);
+ mi_show_error_message(fmt, args);
va_end(args);
- #if (MI_SECURE>=0)
- abort();
- #endif
+ // and call the error handler which may abort (or return normally)
+ if (mi_error_handler != NULL) {
+ mi_error_handler(err, mi_atomic_read_ptr(&mi_error_arg));
+ }
+ else {
+ mi_error_default(err);
+ }
}
// --------------------------------------------------------
diff --git a/src/os.c b/src/os.c
index b5bd0ad9..be507b69 100644
--- a/src/os.c
+++ b/src/os.c
@@ -13,7 +13,7 @@ terms of the MIT license. A copy of the license can be found in the file
#include "mimalloc-atomic.h"
#include // strerror
-#include
+
#if defined(_WIN32)
#include
@@ -655,7 +655,7 @@ static bool mi_os_commitx(void* addr, size_t size, bool commit, bool conservativ
if (err != 0) { err = errno; }
#endif
if (err != 0) {
- _mi_warning_message("%s error: start: 0x%p, csize: 0x%x, err: %i\n", commit ? "commit" : "decommit", start, csize, err);
+ _mi_warning_message("%s error: start: %p, csize: 0x%x, err: %i\n", commit ? "commit" : "decommit", start, csize, err);
mi_mprotect_hint(err);
}
mi_assert_internal(err == 0);
@@ -719,7 +719,7 @@ static bool mi_os_resetx(void* addr, size_t size, bool reset, mi_stats_t* stats)
int err = madvise(start, csize, MADV_DONTNEED);
#endif
if (err != 0) {
- _mi_warning_message("madvise reset error: start: 0x%p, csize: 0x%x, errno: %i\n", start, csize, errno);
+ _mi_warning_message("madvise reset error: start: %p, csize: 0x%x, errno: %i\n", start, csize, errno);
}
//mi_assert(err == 0);
if (err != 0) return false;
@@ -774,7 +774,7 @@ static bool mi_os_protectx(void* addr, size_t size, bool protect) {
if (err != 0) { err = errno; }
#endif
if (err != 0) {
- _mi_warning_message("mprotect error: start: 0x%p, csize: 0x%x, err: %i\n", start, csize, err);
+ _mi_warning_message("mprotect error: start: %p, csize: 0x%x, err: %i\n", start, csize, err);
mi_mprotect_hint(err);
}
return (err == 0);
@@ -961,7 +961,7 @@ void* _mi_os_alloc_huge_os_pages(size_t pages, int numa_node, mi_msecs_t max_mse
if (p != addr) {
// no success, issue a warning and break
if (p != NULL) {
- _mi_warning_message("could not allocate contiguous huge page %zu at 0x%p\n", page, addr);
+ _mi_warning_message("could not allocate contiguous huge page %zu at %p\n", page, addr);
_mi_os_free(p, MI_HUGE_OS_PAGE_SIZE, &_mi_stats_main);
}
break;
diff --git a/src/page.c b/src/page.c
index 84baf306..d67a44de 100644
--- a/src/page.c
+++ b/src/page.c
@@ -175,7 +175,7 @@ static void _mi_page_thread_free_collect(mi_page_t* page)
}
// if `count > max_count` there was a memory corruption (possibly infinite list due to double multi-threaded free)
if (count > max_count) {
- _mi_fatal_error("corrupted thread-free list\n");
+ _mi_error_message(EFAULT, "corrupted thread-free list\n");
return; // the thread-free items cannot be freed
}
@@ -796,7 +796,8 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
mi_page_t* page;
if (mi_unlikely(size > MI_LARGE_OBJ_SIZE_MAX)) {
if (mi_unlikely(size > PTRDIFF_MAX)) { // we don't allocate more than PTRDIFF_MAX (see )
- page = NULL;
+ _mi_error_message(EOVERFLOW, "allocation request is too large (%zu b requested)\n", size);
+ return NULL;
}
else {
page = mi_huge_page_alloc(heap,size);
@@ -806,7 +807,10 @@ void* _mi_malloc_generic(mi_heap_t* heap, size_t size) mi_attr_noexcept
// otherwise find a page with free blocks in our size segregated queues
page = mi_find_free_page(heap,size);
}
- if (page == NULL) return NULL; // out of memory
+ if (mi_unlikely(page == NULL)) { // out of memory
+ _mi_error_message(ENOMEM, "cannot allocate memory (%zu bytes requested)\n", size);
+ return NULL;
+ }
mi_assert_internal(mi_page_immediate_available(page));
mi_assert_internal(mi_page_block_size(page) >= size);
diff --git a/test/test-api.c b/test/test-api.c
index 060efc44..68df314e 100644
--- a/test/test-api.c
+++ b/test/test-api.c
@@ -9,7 +9,7 @@ terms of the MIT license. A copy of the license can be found in the file
Testing allocators is difficult as bugs may only surface after particular
allocation patterns. The main approach to testing _mimalloc_ is therefore
to have extensive internal invariant checking (see `page_is_valid` in `page.c`
-for example), which is enabled in debug mode with `-DMI_CHECK_FULL=ON`.
+for example), which is enabled in debug mode with `-DMI_DEBUG_FULL=ON`.
The main testing is then to run `mimalloc-bench` [1] using full invariant checking
to catch any potential problems over a wide range of intensive allocation bench
marks.
@@ -88,6 +88,10 @@ int main() {
CHECK_BODY("malloc-null",{
mi_free(NULL);
});
+ CHECK_BODY("calloc-overflow",{
+ // use (size_t)&mi_calloc to get some number without triggering compiler warnings
+ result = (mi_calloc((size_t)&mi_calloc,SIZE_MAX/1000) == NULL);
+ });
// ---------------------------------------------------
// Extended