mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-06 15:29:31 +03:00
merge from dev-abandon
This commit is contained in:
commit
bcb8ce94f1
9 changed files with 85 additions and 30 deletions
41
SECURITY.md
Normal file
41
SECURITY.md
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
|
||||||
|
|
||||||
|
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
|
||||||
|
|
||||||
|
## Reporting Security Issues
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
|
||||||
|
|
||||||
|
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
|
||||||
|
|
||||||
|
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
|
||||||
|
|
||||||
|
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||||
|
|
||||||
|
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||||
|
* Full paths of source file(s) related to the manifestation of the issue
|
||||||
|
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||||
|
* Any special configuration required to reproduce the issue
|
||||||
|
* Step-by-step instructions to reproduce the issue
|
||||||
|
* Proof-of-concept or exploit code (if possible)
|
||||||
|
* Impact of the issue, including how an attacker might exploit the issue
|
||||||
|
|
||||||
|
This information will help us triage your report more quickly.
|
||||||
|
|
||||||
|
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
|
||||||
|
|
||||||
|
## Preferred Languages
|
||||||
|
|
||||||
|
We prefer all communications to be in English.
|
||||||
|
|
||||||
|
## Policy
|
||||||
|
|
||||||
|
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
|
||||||
|
|
||||||
|
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
|
@ -597,7 +597,10 @@ typedef struct mi_stats_s {
|
||||||
mi_stat_counter_t searches;
|
mi_stat_counter_t searches;
|
||||||
mi_stat_counter_t normal_count;
|
mi_stat_counter_t normal_count;
|
||||||
mi_stat_counter_t huge_count;
|
mi_stat_counter_t huge_count;
|
||||||
mi_stat_counter_t large_count;
|
mi_stat_counter_t large_count;
|
||||||
|
mi_stat_counter_t arena_count;
|
||||||
|
mi_stat_counter_t arena_crossover_count;
|
||||||
|
mi_stat_counter_t arena_rollback_count;
|
||||||
#if MI_STAT>1
|
#if MI_STAT>1
|
||||||
mi_stat_count_t normal_bins[MI_BIN_HUGE+1];
|
mi_stat_count_t normal_bins[MI_BIN_HUGE+1];
|
||||||
#endif
|
#endif
|
||||||
|
|
17
src/arena.c
17
src/arena.c
|
@ -211,10 +211,10 @@ static void* mi_arena_block_start(mi_arena_t* arena, mi_bitmap_index_t bindex) {
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
// claim the `blocks_inuse` bits
|
// claim the `blocks_inuse` bits
|
||||||
static bool mi_arena_try_claim(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx)
|
static bool mi_arena_try_claim(mi_arena_t* arena, size_t blocks, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats)
|
||||||
{
|
{
|
||||||
size_t idx = 0; // mi_atomic_load_relaxed(&arena->search_idx); // start from last search; ok to be relaxed as the exact start does not matter
|
size_t idx = 0; // mi_atomic_load_relaxed(&arena->search_idx); // start from last search; ok to be relaxed as the exact start does not matter
|
||||||
if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx)) {
|
if (_mi_bitmap_try_find_from_claim_across(arena->blocks_inuse, arena->field_count, idx, blocks, bitmap_idx, stats)) {
|
||||||
mi_atomic_store_relaxed(&arena->search_idx, mi_bitmap_index_field(*bitmap_idx)); // start search from found location next time around
|
mi_atomic_store_relaxed(&arena->search_idx, mi_bitmap_index_field(*bitmap_idx)); // start search from found location next time around
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
@ -233,7 +233,7 @@ static mi_decl_noinline void* mi_arena_try_alloc_at(mi_arena_t* arena, size_t ar
|
||||||
mi_assert_internal(mi_arena_id_index(arena->id) == arena_index);
|
mi_assert_internal(mi_arena_id_index(arena->id) == arena_index);
|
||||||
|
|
||||||
mi_bitmap_index_t bitmap_index;
|
mi_bitmap_index_t bitmap_index;
|
||||||
if (!mi_arena_try_claim(arena, needed_bcount, &bitmap_index)) return NULL;
|
if (!mi_arena_try_claim(arena, needed_bcount, &bitmap_index, tld->stats)) return NULL;
|
||||||
|
|
||||||
// claimed it!
|
// claimed it!
|
||||||
void* p = mi_arena_block_start(arena, bitmap_index);
|
void* p = mi_arena_block_start(arena, bitmap_index);
|
||||||
|
@ -460,7 +460,7 @@ static void mi_arena_purge(mi_arena_t* arena, size_t bitmap_idx, size_t blocks,
|
||||||
// and also undo the decommit stats (as it was already adjusted)
|
// and also undo the decommit stats (as it was already adjusted)
|
||||||
mi_assert_internal(mi_option_is_enabled(mi_option_purge_decommits));
|
mi_assert_internal(mi_option_is_enabled(mi_option_purge_decommits));
|
||||||
needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */, stats);
|
needs_recommit = _mi_os_purge_ex(p, size, false /* allow reset? */, stats);
|
||||||
_mi_stat_increase(&stats->committed, size);
|
if (needs_recommit) { _mi_stat_increase(&_mi_stats_main.committed, size); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the purged blocks
|
// clear the purged blocks
|
||||||
|
@ -617,7 +617,7 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi
|
||||||
// was a direct OS allocation, pass through
|
// was a direct OS allocation, pass through
|
||||||
if (!all_committed && committed_size > 0) {
|
if (!all_committed && committed_size > 0) {
|
||||||
// if partially committed, adjust the committed stats (as `_mi_os_free` will increase decommit by the full size)
|
// if partially committed, adjust the committed stats (as `_mi_os_free` will increase decommit by the full size)
|
||||||
_mi_stat_decrease(&stats->committed, committed_size);
|
_mi_stat_decrease(&_mi_stats_main.committed, committed_size);
|
||||||
}
|
}
|
||||||
_mi_os_free(p, size, memid, stats);
|
_mi_os_free(p, size, memid, stats);
|
||||||
}
|
}
|
||||||
|
@ -660,7 +660,7 @@ void _mi_arena_free(void* p, size_t size, size_t committed_size, mi_memid_t memi
|
||||||
if (committed_size > 0) {
|
if (committed_size > 0) {
|
||||||
// if partially committed, adjust the committed stats (is it will be recommitted when re-using)
|
// if partially committed, adjust the committed stats (is it will be recommitted when re-using)
|
||||||
// in the delayed purge, we now need to not count a decommit if the range is not marked as committed.
|
// in the delayed purge, we now need to not count a decommit if the range is not marked as committed.
|
||||||
_mi_stat_decrease(&stats->committed, committed_size);
|
_mi_stat_decrease(&_mi_stats_main.committed, committed_size);
|
||||||
}
|
}
|
||||||
// note: if not all committed, it may be that the purge will reset/decommit the entire range
|
// note: if not all committed, it may be that the purge will reset/decommit the entire range
|
||||||
// that contains already decommitted parts. Since purge consistently uses reset or decommit that
|
// that contains already decommitted parts. Since purge consistently uses reset or decommit that
|
||||||
|
@ -871,7 +871,7 @@ mi_segment_t* _mi_arena_segment_clear_abandoned_next(mi_arena_field_cursor_t* pr
|
||||||
Add an arena.
|
Add an arena.
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
static bool mi_arena_add(mi_arena_t* arena, mi_arena_id_t* arena_id) {
|
static bool mi_arena_add(mi_arena_t* arena, mi_arena_id_t* arena_id, mi_stats_t* stats) {
|
||||||
mi_assert_internal(arena != NULL);
|
mi_assert_internal(arena != NULL);
|
||||||
mi_assert_internal((uintptr_t)mi_atomic_load_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0);
|
mi_assert_internal((uintptr_t)mi_atomic_load_ptr_relaxed(uint8_t,&arena->start) % MI_SEGMENT_ALIGN == 0);
|
||||||
mi_assert_internal(arena->block_count > 0);
|
mi_assert_internal(arena->block_count > 0);
|
||||||
|
@ -882,6 +882,7 @@ static bool mi_arena_add(mi_arena_t* arena, mi_arena_id_t* arena_id) {
|
||||||
mi_atomic_decrement_acq_rel(&mi_arena_count);
|
mi_atomic_decrement_acq_rel(&mi_arena_count);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
_mi_stat_counter_increase(&stats->arena_count,1);
|
||||||
arena->id = mi_arena_id_create(i);
|
arena->id = mi_arena_id_create(i);
|
||||||
mi_atomic_store_ptr_release(mi_arena_t,&mi_arenas[i], arena);
|
mi_atomic_store_ptr_release(mi_arena_t,&mi_arenas[i], arena);
|
||||||
if (arena_id != NULL) { *arena_id = arena->id; }
|
if (arena_id != NULL) { *arena_id = arena->id; }
|
||||||
|
@ -937,7 +938,7 @@ static bool mi_manage_os_memory_ex2(void* start, size_t size, bool is_large, int
|
||||||
mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post);
|
mi_bitmap_index_t postidx = mi_bitmap_index_create(fields - 1, MI_BITMAP_FIELD_BITS - post);
|
||||||
_mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL);
|
_mi_bitmap_claim(arena->blocks_inuse, fields, post, postidx, NULL);
|
||||||
}
|
}
|
||||||
return mi_arena_add(arena, arena_id);
|
return mi_arena_add(arena, arena_id, &_mi_stats_main);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/bitmap.c
12
src/bitmap.c
|
@ -200,7 +200,7 @@ bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t
|
||||||
// Try to atomically claim a sequence of `count` bits starting from the field
|
// Try to atomically claim a sequence of `count` bits starting from the field
|
||||||
// at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success.
|
// at `idx` in `bitmap` and crossing into subsequent fields. Returns `true` on success.
|
||||||
// Only needs to consider crossing into the next fields (see `mi_bitmap_try_find_from_claim_across`)
|
// Only needs to consider crossing into the next fields (see `mi_bitmap_try_find_from_claim_across`)
|
||||||
static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx)
|
static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bitmap_fields, size_t idx, const size_t count, const size_t retries, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats)
|
||||||
{
|
{
|
||||||
mi_assert_internal(bitmap_idx != NULL);
|
mi_assert_internal(bitmap_idx != NULL);
|
||||||
|
|
||||||
|
@ -260,6 +260,7 @@ static bool mi_bitmap_try_find_claim_field_across(mi_bitmap_t bitmap, size_t bit
|
||||||
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
||||||
|
|
||||||
// claimed!
|
// claimed!
|
||||||
|
mi_stat_counter_increase(stats->arena_crossover_count,1);
|
||||||
*bitmap_idx = mi_bitmap_index_create(idx, initial_idx);
|
*bitmap_idx = mi_bitmap_index_create(idx, initial_idx);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -279,9 +280,10 @@ rollback:
|
||||||
newmap = (map & ~initial_mask);
|
newmap = (map & ~initial_mask);
|
||||||
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
} while (!mi_atomic_cas_strong_acq_rel(field, &map, newmap));
|
||||||
}
|
}
|
||||||
|
mi_stat_counter_increase(stats->arena_rollback_count,1);
|
||||||
// retry? (we make a recursive call instead of goto to be able to use const declarations)
|
// retry? (we make a recursive call instead of goto to be able to use const declarations)
|
||||||
if (retries <= 2) {
|
if (retries <= 2) {
|
||||||
return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx);
|
return mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, retries+1, bitmap_idx, stats);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -291,7 +293,7 @@ rollback:
|
||||||
|
|
||||||
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
||||||
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx) {
|
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats) {
|
||||||
mi_assert_internal(count > 0);
|
mi_assert_internal(count > 0);
|
||||||
if (count <= 2) {
|
if (count <= 2) {
|
||||||
// we don't bother with crossover fields for small counts
|
// we don't bother with crossover fields for small counts
|
||||||
|
@ -303,13 +305,15 @@ bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitm
|
||||||
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
for (size_t visited = 0; visited < bitmap_fields; visited++, idx++) {
|
||||||
if (idx >= bitmap_fields) { idx = 0; } // wrap
|
if (idx >= bitmap_fields) { idx = 0; } // wrap
|
||||||
// first try to claim inside a field
|
// first try to claim inside a field
|
||||||
|
/*
|
||||||
if (count <= MI_BITMAP_FIELD_BITS) {
|
if (count <= MI_BITMAP_FIELD_BITS) {
|
||||||
if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
if (_mi_bitmap_try_find_claim_field(bitmap, idx, count, bitmap_idx)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
// if that fails, then try to claim across fields
|
// if that fails, then try to claim across fields
|
||||||
if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx)) {
|
if (mi_bitmap_try_find_claim_field_across(bitmap, bitmap_fields, idx, count, 0, bitmap_idx, stats)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ bool _mi_bitmap_is_any_claimed(mi_bitmap_t bitmap, size_t bitmap_fields, size_t
|
||||||
|
|
||||||
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
// Find `count` bits of zeros and set them to 1 atomically; returns `true` on success.
|
||||||
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
// Starts at idx, and wraps around to search in all `bitmap_fields` fields.
|
||||||
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx);
|
bool _mi_bitmap_try_find_from_claim_across(mi_bitmap_t bitmap, const size_t bitmap_fields, const size_t start_field_idx, const size_t count, mi_bitmap_index_t* bitmap_idx, mi_stats_t* stats);
|
||||||
|
|
||||||
// Set `count` bits at `bitmap_idx` to 0 atomically
|
// Set `count` bits at `bitmap_idx` to 0 atomically
|
||||||
// Returns `true` if all `count` bits were 1 previously.
|
// Returns `true` if all `count` bits were 1 previously.
|
||||||
|
|
|
@ -84,7 +84,8 @@ const mi_page_t _mi_page_empty = {
|
||||||
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
MI_STAT_COUNT_NULL(), MI_STAT_COUNT_NULL(), \
|
||||||
MI_STAT_COUNT_NULL(), \
|
MI_STAT_COUNT_NULL(), \
|
||||||
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
|
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
|
||||||
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } \
|
{ 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, \
|
||||||
|
{ 0, 0 }, { 0, 0 }, { 0, 0 } \
|
||||||
MI_STAT_COUNT_END_NULL()
|
MI_STAT_COUNT_END_NULL()
|
||||||
|
|
||||||
|
|
||||||
|
|
25
src/os.c
25
src/os.c
|
@ -133,13 +133,13 @@ static void mi_os_free_huge_os_pages(void* p, size_t size, mi_stats_t* stats);
|
||||||
|
|
||||||
static void mi_os_prim_free(void* addr, size_t size, bool still_committed, mi_stats_t* tld_stats) {
|
static void mi_os_prim_free(void* addr, size_t size, bool still_committed, mi_stats_t* tld_stats) {
|
||||||
MI_UNUSED(tld_stats);
|
MI_UNUSED(tld_stats);
|
||||||
|
mi_stats_t* stats = &_mi_stats_main;
|
||||||
mi_assert_internal((size % _mi_os_page_size()) == 0);
|
mi_assert_internal((size % _mi_os_page_size()) == 0);
|
||||||
if (addr == NULL || size == 0) return; // || _mi_os_is_huge_reserved(addr)
|
if (addr == NULL || size == 0) return; // || _mi_os_is_huge_reserved(addr)
|
||||||
int err = _mi_prim_free(addr, size);
|
int err = _mi_prim_free(addr, size);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
_mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr);
|
_mi_warning_message("unable to free OS memory (error: %d (0x%x), size: 0x%zx bytes, address: %p)\n", err, err, size, addr);
|
||||||
}
|
}
|
||||||
mi_stats_t* stats = &_mi_stats_main;
|
|
||||||
if (still_committed) { _mi_stat_decrease(&stats->committed, size); }
|
if (still_committed) { _mi_stat_decrease(&stats->committed, size); }
|
||||||
_mi_stat_decrease(&stats->reserved, size);
|
_mi_stat_decrease(&stats->reserved, size);
|
||||||
}
|
}
|
||||||
|
@ -180,20 +180,22 @@ void _mi_os_free(void* p, size_t size, mi_memid_t memid, mi_stats_t* tld_stats)
|
||||||
-------------------------------------------------------------- */
|
-------------------------------------------------------------- */
|
||||||
|
|
||||||
// Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned.
|
// Note: the `try_alignment` is just a hint and the returned pointer is not guaranteed to be aligned.
|
||||||
static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* stats) {
|
static void* mi_os_prim_alloc(size_t size, size_t try_alignment, bool commit, bool allow_large, bool* is_large, bool* is_zero, mi_stats_t* tld_stats) {
|
||||||
mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0);
|
mi_assert_internal(size > 0 && (size % _mi_os_page_size()) == 0);
|
||||||
mi_assert_internal(is_zero != NULL);
|
mi_assert_internal(is_zero != NULL);
|
||||||
mi_assert_internal(is_large != NULL);
|
mi_assert_internal(is_large != NULL);
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
if (!commit) { allow_large = false; }
|
if (!commit) { allow_large = false; }
|
||||||
if (try_alignment == 0) { try_alignment = 1; } // avoid 0 to ensure there will be no divide by zero when aligning
|
if (try_alignment == 0) { try_alignment = 1; } // avoid 0 to ensure there will be no divide by zero when aligning
|
||||||
|
|
||||||
*is_zero = false;
|
*is_zero = false;
|
||||||
void* p = NULL;
|
void* p = NULL;
|
||||||
int err = _mi_prim_alloc(size, try_alignment, commit, allow_large, is_large, is_zero, &p);
|
int err = _mi_prim_alloc(size, try_alignment, commit, allow_large, is_large, is_zero, &p);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
_mi_warning_message("unable to allocate OS memory (error: %d (0x%x), size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, size, try_alignment, commit, allow_large);
|
_mi_warning_message("unable to allocate OS memory (error: %d (0x%x), size: 0x%zx bytes, align: 0x%zx, commit: %d, allow large: %d)\n", err, err, size, try_alignment, commit, allow_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MI_UNUSED(tld_stats);
|
||||||
|
mi_stats_t* stats = &_mi_stats_main;
|
||||||
mi_stat_counter_increase(stats->mmap_calls, 1);
|
mi_stat_counter_increase(stats->mmap_calls, 1);
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
_mi_stat_increase(&stats->reserved, size);
|
_mi_stat_increase(&stats->reserved, size);
|
||||||
|
@ -281,10 +283,8 @@ static void* mi_os_prim_alloc_aligned(size_t size, size_t alignment, bool commit
|
||||||
OS API: alloc and alloc_aligned
|
OS API: alloc and alloc_aligned
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* tld_stats) {
|
void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* stats) {
|
||||||
MI_UNUSED(tld_stats);
|
|
||||||
*memid = _mi_memid_none();
|
*memid = _mi_memid_none();
|
||||||
mi_stats_t* stats = &_mi_stats_main;
|
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
size = _mi_os_good_alloc_size(size);
|
size = _mi_os_good_alloc_size(size);
|
||||||
bool os_is_large = false;
|
bool os_is_large = false;
|
||||||
|
@ -296,10 +296,9 @@ void* _mi_os_alloc(size_t size, mi_memid_t* memid, mi_stats_t* tld_stats) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* tld_stats)
|
void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* stats)
|
||||||
{
|
{
|
||||||
MI_UNUSED(&_mi_os_get_aligned_hint); // suppress unused warnings
|
MI_UNUSED(&_mi_os_get_aligned_hint); // suppress unused warnings
|
||||||
MI_UNUSED(tld_stats);
|
|
||||||
*memid = _mi_memid_none();
|
*memid = _mi_memid_none();
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
size = _mi_os_good_alloc_size(size);
|
size = _mi_os_good_alloc_size(size);
|
||||||
|
@ -308,7 +307,7 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo
|
||||||
bool os_is_large = false;
|
bool os_is_large = false;
|
||||||
bool os_is_zero = false;
|
bool os_is_zero = false;
|
||||||
void* os_base = NULL;
|
void* os_base = NULL;
|
||||||
void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base, &_mi_stats_main /*tld->stats*/ );
|
void* p = mi_os_prim_alloc_aligned(size, alignment, commit, allow_large, &os_is_large, &os_is_zero, &os_base, stats );
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
*memid = _mi_memid_create_os(commit, os_is_zero, os_is_large);
|
*memid = _mi_memid_create_os(commit, os_is_zero, os_is_large);
|
||||||
memid->mem.os.base = os_base;
|
memid->mem.os.base = os_base;
|
||||||
|
@ -325,7 +324,7 @@ void* _mi_os_alloc_aligned(size_t size, size_t alignment, bool commit, bool allo
|
||||||
to use the actual start of the memory region.
|
to use the actual start of the memory region.
|
||||||
----------------------------------------------------------- */
|
----------------------------------------------------------- */
|
||||||
|
|
||||||
void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offset, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* tld_stats) {
|
void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offset, bool commit, bool allow_large, mi_memid_t* memid, mi_stats_t* stats) {
|
||||||
mi_assert(offset <= MI_SEGMENT_SIZE);
|
mi_assert(offset <= MI_SEGMENT_SIZE);
|
||||||
mi_assert(offset <= size);
|
mi_assert(offset <= size);
|
||||||
mi_assert((alignment % _mi_os_page_size()) == 0);
|
mi_assert((alignment % _mi_os_page_size()) == 0);
|
||||||
|
@ -333,20 +332,20 @@ void* _mi_os_alloc_aligned_at_offset(size_t size, size_t alignment, size_t offse
|
||||||
if (offset > MI_SEGMENT_SIZE) return NULL;
|
if (offset > MI_SEGMENT_SIZE) return NULL;
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
// regular aligned allocation
|
// regular aligned allocation
|
||||||
return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid, tld_stats);
|
return _mi_os_alloc_aligned(size, alignment, commit, allow_large, memid, stats);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// overallocate to align at an offset
|
// overallocate to align at an offset
|
||||||
const size_t extra = _mi_align_up(offset, alignment) - offset;
|
const size_t extra = _mi_align_up(offset, alignment) - offset;
|
||||||
const size_t oversize = size + extra;
|
const size_t oversize = size + extra;
|
||||||
void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid, tld_stats);
|
void* const start = _mi_os_alloc_aligned(oversize, alignment, commit, allow_large, memid, stats);
|
||||||
if (start == NULL) return NULL;
|
if (start == NULL) return NULL;
|
||||||
|
|
||||||
void* const p = (uint8_t*)start + extra;
|
void* const p = (uint8_t*)start + extra;
|
||||||
mi_assert(_mi_is_aligned((uint8_t*)p + offset, alignment));
|
mi_assert(_mi_is_aligned((uint8_t*)p + offset, alignment));
|
||||||
// decommit the overallocation at the start
|
// decommit the overallocation at the start
|
||||||
if (commit && extra > _mi_os_page_size()) {
|
if (commit && extra > _mi_os_page_size()) {
|
||||||
_mi_os_decommit(start, extra, tld_stats);
|
_mi_os_decommit(start, extra, stats);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,9 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
#if !TARGET_IOS_IPHONE && !TARGET_IOS_SIMULATOR
|
#if !TARGET_IOS_IPHONE && !TARGET_IOS_SIMULATOR
|
||||||
#include <mach/vm_statistics.h>
|
#include <mach/vm_statistics.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(MAC_OS_X_VERSION_10_7)
|
||||||
|
#define MAC_OS_X_VERSION_10_7 1070
|
||||||
|
#endif
|
||||||
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
#elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#if __FreeBSD_version >= 1200000
|
#if __FreeBSD_version >= 1200000
|
||||||
|
@ -83,7 +86,7 @@ static int mi_prim_access(const char *fpath, int mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif !defined(__sun) && \
|
#elif !defined(__sun) && \
|
||||||
(!defined(__APPLE__) || (defined(MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7))) // avoid unused warnings on macOS and Solaris
|
(!defined(__APPLE__) || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7)) // avoid unused warnings on macOS and Solaris
|
||||||
|
|
||||||
static int mi_prim_open(const char* fpath, int open_flags) {
|
static int mi_prim_open(const char* fpath, int open_flags) {
|
||||||
return open(fpath,open_flags);
|
return open(fpath,open_flags);
|
||||||
|
@ -759,7 +762,7 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) {
|
||||||
#elif defined(__ANDROID__) || defined(__DragonFly__) || \
|
#elif defined(__ANDROID__) || defined(__DragonFly__) || \
|
||||||
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \
|
||||||
defined(__sun) || \
|
defined(__sun) || \
|
||||||
(defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7))
|
(defined(__APPLE__) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7))
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
bool _mi_prim_random_buf(void* buf, size_t buf_len) {
|
bool _mi_prim_random_buf(void* buf, size_t buf_len) {
|
||||||
|
|
|
@ -340,6 +340,9 @@ static void _mi_stats_print(mi_stats_t* stats, mi_output_fun* out0, void* arg0)
|
||||||
mi_stat_print(&stats->pages_abandoned, "-abandoned", -1, out, arg);
|
mi_stat_print(&stats->pages_abandoned, "-abandoned", -1, out, arg);
|
||||||
mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg);
|
mi_stat_counter_print(&stats->pages_extended, "-extended", out, arg);
|
||||||
mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg);
|
mi_stat_counter_print(&stats->page_no_retire, "-noretire", out, arg);
|
||||||
|
mi_stat_counter_print(&stats->arena_count, "arenas", out, arg);
|
||||||
|
mi_stat_counter_print(&stats->arena_crossover_count, "-crossover", out, arg);
|
||||||
|
mi_stat_counter_print(&stats->arena_rollback_count, "-rollback", out, arg);
|
||||||
mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg);
|
mi_stat_counter_print(&stats->mmap_calls, "mmaps", out, arg);
|
||||||
mi_stat_counter_print(&stats->commit_calls, "commits", out, arg);
|
mi_stat_counter_print(&stats->commit_calls, "commits", out, arg);
|
||||||
mi_stat_counter_print(&stats->reset_calls, "resets", out, arg);
|
mi_stat_counter_print(&stats->reset_calls, "resets", out, arg);
|
||||||
|
|
Loading…
Add table
Reference in a new issue