Loading...
--- libmalloc/libmalloc-409.60.6/src/nanov2_malloc.c
+++ libmalloc/libmalloc-521.120.7/src/nanov2_malloc.c
@@ -1517,9 +1517,7 @@
kern_return_t kr;
bitarray_t slots;
- if (!reader) {
- reader = nano_common_default_reader;
- }
+ reader = reader_or_in_memory_fallback(reader, task);
kr = reader(task, zone_address, sizeof(nanozonev2_t), (void **)&nanozone);
if (kr) {
@@ -1624,7 +1622,7 @@
bitarray_zap(slots, log_size, next_slot);
void *ptr = nanov2_slot_in_block_ptr(blockp, size_class, next_slot);
nanov2_free_slot_t *slotp = NANOV2_ZONE_PTR_TO_MAPPED_PTR(nanov2_free_slot_t *, ptr, ptr_offset);
- next_slot = slotp->next_slot;
+ next_slot = (uint16_t)slotp->next_slot;
free_list_count++;
}
// Add a range for each slot that is not on the freelist,
@@ -1643,7 +1641,7 @@
ranges[range_count].size = slot_size;
range_count++;
}
- free(slots);
+ _free(slots);
}
if (range_count) {
// Notify the in-use pointers that we found.
@@ -1960,7 +1958,7 @@
malloc_statistics_t *stats)
{
printer = printer ? printer : nanov2_null_printer;
- reader = !reader && task == mach_task_self() ? _malloc_default_reader : reader;
+ reader = reader_or_in_memory_fallback(reader, task);
kern_return_t err;
@@ -2292,26 +2290,49 @@
#if OS_VARIANT_NOTRESOLVED
-#if NANOV2_MULTIPLE_REGIONS
-static nanov2_addr_t nanov2_max_region_base = {
- .fields.nano_signature = NANOZONE_SIGNATURE,
- .fields.nano_region = NANOV2_MAX_REGION_NUMBER
-};
-#endif // NANOV2_MULTIPLE_REGIONS
-
+#if CONFIG_NANO_RESERVE_REGIONS
+// Update protection for region to DEFAULT
+static bool
+nanov2_unprotect_region(nanov2_region_t *region)
+{
+ MALLOC_TRACE(TRACE_nanov2_region_protection | DBG_FUNC_START,
+ (uint64_t)region, 0, 0, 0);
+ bool result = nano_common_unprotect_vm_space((mach_vm_address_t)region,
+ NANOV2_REGION_SIZE);
+ MALLOC_TRACE(TRACE_nanov2_region_protection | DBG_FUNC_END,
+ (uint64_t)region, result, 0, 0);
+ return result;
+}
+
+// Reserve VA at [base, base+num_regions*REGION_SIZE].
+// Note: permissions must still be granted on reserved region with `nanov2_unprotect_region`
+static bool
+nanov2_reserve_regions(nanov2_region_t *base, unsigned int num_regions)
+{
+ MALLOC_TRACE(TRACE_nanov2_region_reservation | DBG_FUNC_START,
+ (uint64_t)base, num_regions, 0, 0);
+ bool result = nano_common_reserve_vm_space((mach_vm_address_t)base,
+ (NANOV2_REGION_SIZE * (mach_vm_size_t)num_regions));
+ MALLOC_TRACE(TRACE_nanov2_region_reservation | DBG_FUNC_END,
+ (uint64_t)base, num_regions, result, 0);
+
+ return result;
+}
+#else
// Attempts to allocate VM space for a region at a given address and returns
// whether the allocation succeeded.
-static boolean_t
+static bool
nanov2_allocate_region(nanov2_region_t *region)
{
MALLOC_TRACE(TRACE_nanov2_region_allocation | DBG_FUNC_START,
(uint64_t)region, 0, 0, 0);
- boolean_t result = nano_common_allocate_vm_space((mach_vm_address_t)region,
+ bool result = nano_common_allocate_vm_space((mach_vm_address_t)region,
NANOV2_REGION_SIZE);
MALLOC_TRACE(TRACE_nanov2_region_allocation | DBG_FUNC_END,
(uint64_t)region, result, 0, 0);
return result;
}
+#endif // CONFIG_NANO_RESERVE_REGIONS
// Allocates a new region adjacent to the current one. If the allocation fails,
// keep sliding up by the size of a region until we either succeed or run out of
@@ -2323,11 +2344,26 @@
#if NANOV2_MULTIPLE_REGIONS
bool allocated = false;
+ nanov2_addr_t nanov2_max_region_base = {
+ .fields.nano_signature = NANOZONE_SIGNATURE,
+ .fields.nano_region = nano_max_region,
+ };
+
_malloc_lock_assert_owner(&nanozone->regions_lock);
nanov2_region_t *current_region = nanov2_current_region_base(
os_atomic_load(&nanozone->current_region_next_arena, relaxed));
nanov2_region_t *next_region = current_region + 1;
+
while ((void *)next_region <= nanov2_max_region_base.addr) {
+#if CONFIG_NANO_RESERVE_REGIONS
+ if (!nanov2_unprotect_region(next_region)) {
+ MALLOC_REPORT_FATAL_ERROR(next_region,
+ "Nano: Unable to raise protection on pre-allocated region");
+ }
+ nanozone->statistics.allocated_regions++;
+ allocated = true;
+ break;
+#else // CONFIG_NANO_RESERVE_REGIONS
if (nanov2_allocate_region(next_region)) {
nanozone->statistics.allocated_regions++;
allocated = true;
@@ -2340,6 +2376,7 @@
// atomically here. Published by the store-release of
// current_region_next_arena.
os_atomic_inc(&nanozone->statistics.region_address_clashes, relaxed);
+#endif // CONFIG_NANO_RESERVE_REGIONS
}
if (!allocated) {
@@ -2387,7 +2424,8 @@
uint64_t guard = *(uint64_t *)corrupt_slot;
malloc_zone_error(MALLOC_ABORT_ON_CORRUPTION, true,
"Heap corruption detected, free list is damaged at %p\n"
- "*** Incorrect guard value: %lu\n", corrupt_slot, guard);
+ "*** Incorrect guard value: %llu\n", corrupt_slot,
+ (unsigned long long)guard);
__builtin_unreachable();
}
@@ -2452,7 +2490,7 @@
slot = old_meta_view.meta.next_slot - 1; // meta.next_slot is 1-based.
ptr = nanov2_slot_in_block_ptr(blockp, size_class, slot);
nanov2_free_slot_t *slotp = (nanov2_free_slot_t *)ptr;
- new_meta.next_slot = slot_full ? SLOT_FULL : slotp->next_slot;
+ new_meta.next_slot = slot_full ? SLOT_FULL : (uint16_t)slotp->next_slot;
}
// Write the updated meta data; try again if we raced with another thread.
@@ -3059,11 +3097,9 @@
malloc_zone_t *
nanov2_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags)
{
- // Note: It is important that nanov2_create_zone resets _malloc_engaged_nano
- // if it is unable to enable the nanozone (and chooses not to abort). As
- // several functions rely on _malloc_engaged_nano to determine if they
- // should manipulate the nanozone, and these should not run if we failed
- // to create the zone.
+ // Note: It is not necessary that nanov2_create_zone resets _malloc_engaged_nano
+ // if it is unable to enable the nanozone - functions that need to determine
+ // whether the nanozone is preset should test initial_nano_zone.
MALLOC_ASSERT(_malloc_engaged_nano == NANO_V2);
// Get memory for the zone and disable Nano if we fail.
@@ -3135,14 +3171,30 @@
_malloc_lock_init(&nanozone->madvise_lock);
// Allocate the initial region. If this does not succeed, we disable Nano.
- nanov2_addr_t p = {.fields.nano_signature = NANOZONE_SIGNATURE};
- nanov2_region_t *region = (nanov2_region_t *)p.addr;
- boolean_t result = nanov2_allocate_region(region);
+ nanov2_region_t *region = (nanov2_region_t *)NANOZONE_BASE_REGION_ADDRESS;
+
+ bool result;
+#if CONFIG_NANO_RESERVE_REGIONS
+ unsigned int num_regions = (nano_max_region + 1);
+ result = nanov2_reserve_regions(region, num_regions);
+ if (result) {
+ result = nanov2_unprotect_region(region);
+ if (!result) {
+ malloc_report(ASL_LEVEL_ERR,
+ "unable to protect initial region\n");
+ nano_common_deallocate_pages((void *)region,
+ num_regions * (size_t)NANOV2_REGION_SIZE, 0);
+ }
+ }
+#else // CONFIG_NANO_RESERVE_REGIONS
+ result = nanov2_allocate_region(region);
+#endif // CONFIG_NANO_RESERVE_REGIONS
if (!result) {
- nano_common_deallocate_pages(nanozone, NANOZONEV2_ZONE_PAGED_SIZE, 0);
+ nano_common_deallocate_pages((void *)nanozone,
+ NANOZONEV2_ZONE_PAGED_SIZE, 0);
_malloc_engaged_nano = NANO_NONE;
malloc_report(ASL_LEVEL_NOTICE, "nano zone abandoned due to inability "
- "to preallocate reserved vm space.\n");
+ "to reserve vm space.\n");
return NULL;
}
nanov2_region_linkage_t *region_linkage =
@@ -3154,7 +3206,6 @@
os_atomic_store(&nanozone->current_region_next_arena,
((nanov2_arena_t *)region) + 1, release);
nanozone->statistics.allocated_regions = 1;
-
// Set up the guard blocks for the initial arena, if requested
nanov2_init_guard_blocks(nanozone, (nanov2_arena_t *)region);