Loading...
--- libmalloc/libmalloc-166.200.60/src/nano_malloc.c
+++ libmalloc/libmalloc-140.40.1/src/nano_malloc.c
@@ -27,19 +27,131 @@
#if CONFIG_NANOZONE
/********************* PROTOTYPES ***********************/
+// msg prints after fmt, ...
+static MALLOC_NOINLINE void
+nanozone_error(nanozone_t *nanozone, int is_corruption, const char *msg, const void *ptr, const char *fmt, ...) __printflike(5, 6);
static void nano_statistics(nanozone_t *nanozone, malloc_statistics_t *stats);
/********************* VERY LOW LEVEL UTILITIES ************************/
// msg prints after fmt, ...
-static MALLOC_ALWAYS_INLINE unsigned int
-nano_mag_index(const nanozone_t *nanozone)
-{
- if (os_likely(_os_cpu_number_override == -1)) {
- return (_os_cpu_number() >> hyper_shift) % nano_common_max_magazines;
- }
- return (_os_cpu_number_override >> hyper_shift) % nano_common_max_magazines;
+static MALLOC_NOINLINE void
+nanozone_error(nanozone_t *nanozone, int is_corruption, const char *msg, const void *ptr, const char *fmt, ...)
+{
+ va_list ap;
+ _SIMPLE_STRING b = _simple_salloc();
+
+ if (b) {
+ if (fmt) {
+ va_start(ap, fmt);
+ _simple_vsprintf(b, fmt, ap);
+ va_end(ap);
+ }
+ if (ptr) {
+ _simple_sprintf(b, "*** error for object %p: %s\n", ptr, msg);
+ } else {
+ _simple_sprintf(b, "*** error: %s\n", msg);
+ }
+ malloc_printf("%s*** set a breakpoint in malloc_error_break to debug\n", _simple_string(b));
+ } else {
+ /*
+ * Should only get here if vm_allocate() can't get a single page of
+ * memory, implying _simple_asl_log() would also fail. So we just
+ * print to the file descriptor.
+ */
+ if (fmt) {
+ va_start(ap, fmt);
+ _malloc_vprintf(MALLOC_PRINTF_NOLOG, fmt, ap);
+ va_end(ap);
+ }
+ if (ptr) {
+ _malloc_printf(MALLOC_PRINTF_NOLOG, "*** error for object %p: %s\n", ptr, msg);
+ } else {
+ _malloc_printf(MALLOC_PRINTF_NOLOG, "*** error: %s\n", msg);
+ }
+ _malloc_printf(MALLOC_PRINTF_NOLOG, "*** set a breakpoint in malloc_error_break to debug\n");
+ }
+ malloc_error_break();
+
+ // Call abort() if this is a memory corruption error and the abort on
+ // corruption flag is set, or if any error should abort.
+ if ((is_corruption && (nanozone->debug_flags & MALLOC_ABORT_ON_CORRUPTION)) ||
+ (nanozone->debug_flags & MALLOC_ABORT_ON_ERROR)) {
+ _os_set_crash_log_message_dynamic(b ? _simple_string(b) : msg);
+ abort();
+ } else if (b) {
+ _simple_sfree(b);
+ }
+}
+
+static void *
+allocate_based_pages(nanozone_t *nanozone,
+ size_t size,
+ unsigned char align,
+ unsigned debug_flags,
+ int vm_page_label,
+ void *base_addr)
+{
+ boolean_t add_guard_pages = debug_flags & MALLOC_ADD_GUARD_PAGES;
+ mach_vm_address_t vm_addr;
+ uintptr_t addr;
+ mach_vm_size_t allocation_size = round_page(size);
+ mach_vm_offset_t allocation_mask = ((mach_vm_offset_t)1 << align) - 1;
+ int alloc_flags = VM_FLAGS_ANYWHERE | VM_MAKE_TAG(vm_page_label);
+ kern_return_t kr;
+
+ if (!allocation_size) {
+ allocation_size = vm_page_size;
+ }
+ if (add_guard_pages) {
+ allocation_size += 2 * vm_page_size;
+ }
+ if (allocation_size < size) { // size_t arithmetic wrapped!
+ return NULL;
+ }
+
+ vm_addr = round_page((mach_vm_address_t)base_addr);
+ if (!vm_addr) {
+ vm_addr = vm_page_size;
+ }
+ kr = mach_vm_map(mach_task_self(), &vm_addr, allocation_size, allocation_mask, alloc_flags, MEMORY_OBJECT_NULL, 0, FALSE,
+ VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
+ if (kr) {
+ nanozone_error(nanozone, 0, "can't allocate pages", NULL, "*** mach_vm_map(size=%lu) failed (error code=%d)\n", size, kr);
+ return NULL;
+ }
+ addr = (uintptr_t)vm_addr;
+
+ if (add_guard_pages) {
+ addr += vm_page_size;
+ mvm_protect((void *)addr, size, PROT_NONE, debug_flags);
+ }
+ return (void *)addr;
+}
+
+static void *
+nano_allocate_pages(nanozone_t *nanozone, size_t size, unsigned char align, unsigned debug_flags, int vm_page_label)
+{
+ return allocate_based_pages(nanozone, size, align, debug_flags, vm_page_label, 0);
+}
+
+static void
+nano_deallocate_pages(nanozone_t *nanozone, void *addr, size_t size, unsigned debug_flags)
+{
+ boolean_t add_guard_pages = debug_flags & MALLOC_ADD_GUARD_PAGES;
+ mach_vm_address_t vm_addr = (mach_vm_address_t)addr;
+ mach_vm_size_t allocation_size = size;
+ kern_return_t kr;
+
+ if (add_guard_pages) {
+ vm_addr -= vm_page_size;
+ allocation_size += 2 * vm_page_size;
+ }
+ kr = mach_vm_deallocate(mach_task_self(), vm_addr, allocation_size);
+ if (kr && nanozone) {
+ nanozone_error(nanozone, 0, "Can't deallocate_pages at", addr, NULL);
+ }
}
#if NANO_PREALLOCATE_BAND_VM
@@ -54,13 +166,29 @@
u.fields.nano_band = 0;
u.fields.nano_slot = 0;
u.fields.nano_offset = 0;
+
s = u.addr; // start of first possible band
u.fields.nano_mag_index = (1 << NANO_MAG_BITS) - 1;
u.fields.nano_band = (1 << NANO_BAND_BITS) - 1;
+
e = u.addr + BAND_SIZE; // end of last possible band
- return nano_common_allocate_vm_space(s, e - s);
+ mach_vm_address_t vm_addr = s;
+ mach_vm_size_t vm_size = (e - s);
+
+ kern_return_t kr = mach_vm_map(mach_task_self(), &vm_addr, vm_size, 0,
+ VM_MAKE_TAG(VM_MEMORY_MALLOC_NANO), MEMORY_OBJECT_NULL, 0, FALSE,
+ VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
+
+ void *q = (void *)vm_addr;
+ if (kr || q != (void*)s) { // Must get exactly what we asked for
+ if (!kr) {
+ mach_vm_deallocate(mach_task_self(), vm_addr, vm_size);
+ }
+ return FALSE;
+ }
+ return TRUE;
}
#endif
@@ -164,7 +292,6 @@
return (void *)b; // Yep, so the slot_bump_addr this thread incremented is good to go
} else {
if (pMeta->slot_exhausted) { // exhausted all the bands availble for this slot?
- pMeta->slot_bump_addr = theLimit;
return 0; // We're toast
} else {
// One thread will grow the heap, others will see its been grown and retry allocation
@@ -181,7 +308,6 @@
continue; // ... the slot has been successfully grown by us. Now try again.
} else {
pMeta->slot_exhausted = TRUE;
- pMeta->slot_bump_addr = theLimit;
_malloc_lock_unlock(&nanozone->band_resupply_lock[mag_index]);
return 0;
}
@@ -242,7 +368,7 @@
kern_return_t err;
unsigned count = 0;
- for (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {
+ for (mag_index = 0; mag_index < nanozone->phys_ncpus; mag_index++) {
uintptr_t clone_magazine; // magazine base for ourselves
nano_blk_addr_t p; // slot base for remote
uintptr_t clone_slot_base; // slot base for ourselves (tracks with "p")
@@ -302,6 +428,50 @@
uintptr_t slot_band, clone_slot_band_base = clone_slot_base;
uintptr_t skip_adj = index_to_offset(nanozone, pMeta, (index_t)pMeta->slot_objects_skipped);
+ while (q.addr < pMeta->slot_limit_addr) {
+ // read slot in each remote band. Lands in some random location.
+ size_t len = MIN(pMeta->slot_bump_addr - q.addr, SLOT_IN_BAND_SIZE);
+ err = reader(task, (vm_address_t)(q.addr + skip_adj), len - skip_adj, (void **)&slot_band);
+ if (err) {
+ return err;
+ }
+
+ // Place the data just read in the correct position relative to the local magazine.
+ memcpy((void *)(clone_slot_band_base + skip_adj), (void *)slot_band, len - skip_adj);
+
+ // Simultaneously advance pointers in remote and ourselves to the next band.
+ q.addr += BAND_SIZE;
+ clone_slot_band_base += BAND_SIZE;
+ skip_adj = 0;
+ }
+
+ // Walk the slot free list and populate a bitarray_t
+ int log_size = 64 - __builtin_clzl(slot_objects_mapped);
+ bitarray_t slot_bitarray = bitarray_create(log_size);
+
+ if (!slot_bitarray) {
+ return errno;
+ }
+
+ chained_block_t t;
+ unsigned stoploss = (unsigned)slot_objects_mapped;
+ while ((t = OSAtomicDequeue(
+ &(pMeta->slot_LIFO), offsetof(struct chained_block_s, next) + (clone_slot_base - p.addr)))) {
+ if (0 == stoploss) {
+ malloc_printf("Free list walk in segregated_in_use_enumerator exceeded object count.");
+ break;
+ }
+ stoploss--;
+
+ uintptr_t offset = ((uintptr_t)t - p.addr); // offset from beginning of slot, task-independent
+ index_t block_index = offset_to_index(nanozone, pMeta, offset);
+
+ if (block_index < slot_objects_mapped) {
+ bitarray_set(slot_bitarray, log_size, block_index);
+ }
+ }
+ // N.B. pMeta->slot_LIFO in *this* task is now drained (remote free list has *not* been disturbed)
+
// Copy the bitarray_t denoting madvise()'d pages (if any) into *this* task's address space
bitarray_t madv_page_bitarray;
int log_page_count;
@@ -317,99 +487,6 @@
madv_page_bitarray = NULL;
log_page_count = 0;
}
-
- while (q.addr < pMeta->slot_limit_addr) {
- // read slot in each remote band. Lands in some random location. Do not read
- // parts of the slot that are in madvised pages.
- if (!madv_page_bitarray) {
- // Nothing madvised yet - read everything in one go.
- size_t len = MIN(pMeta->slot_bump_addr - q.addr, SLOT_IN_BAND_SIZE) - skip_adj;
- err = reader(task, (vm_address_t)(q.addr + skip_adj), len, (void **)&slot_band);
- if (err) {
- return err;
- }
-
- // Place the data just read in the correct position relative to the local magazine.
- memcpy((void *)(clone_slot_band_base + skip_adj), (void *)slot_band, len);
- } else {
- // We madvised at least one page. Read only the pages that
- // have not been madvised. If bitarray_t had operations
- // like "get next bit set after a given bit" and "find
- // next unset bit after a given bit", we could do this more
- // efficiently but given that it doesn't, we have to walk
- // through each page individually. In practice this is not
- // much of an issue because this code is only used by
- // sampling tools and the additional time required is not
- // really noticeable.
- size_t len = MIN(pMeta->slot_bump_addr - q.addr, SLOT_IN_BAND_SIZE) - skip_adj;
- vm_address_t start_addr = (vm_address_t)(q.addr + skip_adj);
- vm_address_t end_addr = (vm_address_t)(start_addr + len);
- void *target_addr = (void *)(clone_slot_band_base + skip_adj);
- for (vm_address_t addr = start_addr; addr < end_addr;) {
- vm_address_t next_page_addr = trunc_page_kernel(addr + vm_kernel_page_size);
- size_t read_size = MIN(len, next_page_addr - addr);
-
- boolean_t madvised = false;
- nano_blk_addr_t r;
- r.addr = addr;
- index_t pgnum = ((((unsigned)r.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)r.fields.nano_offset)) >>
- vm_kernel_page_shift;
- unsigned int log_page_count = pMeta->slot_madvised_log_page_count;
- madvised = (pgnum < (1 << log_page_count)) &&
- bitarray_get(madv_page_bitarray, log_page_count, pgnum);
- if (!madvised) {
- // This is not an madvised page - grab the data.
- err = reader(task, addr, read_size, (void **)&slot_band);
- if (err) {
- return err;
- }
-
- // Place the data just read in the correct position relative to the local magazine.
- memcpy(target_addr, (void *)slot_band, read_size);
- } else {
- // This is an madvised page - there should be nothing in here that's
- // on the freelist, so just write garbage to the target memory.
- memset(target_addr, (char)0xee, read_size);
- }
- addr = next_page_addr;
- target_addr += read_size;
- len -= read_size;
- }
- }
-
- // Simultaneously advance pointers in remote and ourselves to the next band.
- q.addr += BAND_SIZE;
- clone_slot_band_base += BAND_SIZE;
- skip_adj = 0;
- }
-
- // Walk the slot free list and populate a bitarray_t
- int log_size = 64 - __builtin_clzl(slot_objects_mapped);
- bitarray_t slot_bitarray = bitarray_create(log_size);
-
- if (!slot_bitarray) {
- return errno;
- }
-
- chained_block_t t;
- unsigned stoploss = (unsigned)slot_objects_mapped;
- while ((t = OSAtomicDequeue(
- &(pMeta->slot_LIFO), offsetof(struct chained_block_s, next) + (clone_slot_base - p.addr)))) {
- if (0 == stoploss) {
- malloc_report(ASL_LEVEL_ERR, "Free list walk in segregated_in_use_enumerator exceeded object count.\n");
- break;
- }
- stoploss--;
-
- uintptr_t offset = ((uintptr_t)t - p.addr); // offset from beginning of slot, task-independent
- index_t block_index = offset_to_index(nanozone, pMeta, offset);
-
- if (block_index < slot_objects_mapped) {
- bitarray_set(slot_bitarray, log_size, block_index);
- }
- }
- // N.B. pMeta->slot_LIFO in *this* task is now drained (remote free list has *not* been disturbed)
-
// Enumerate all the block indices issued to date, and report those not on the free list
index_t i;
@@ -489,9 +566,8 @@
unsigned stoploss = (unsigned)pMeta->slot_objects_mapped;
while ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {
if (0 == stoploss) {
- malloc_zone_error(nanozone->debug_flags, true,
- "Free list walk for slot %p in _nano_block_inuse_p exceeded object count.\n",
- (void *)&(pMeta->slot_LIFO));
+ nanozone_error(
+ nanozone, 1, "Free list walk in _nano_block_inuse_p exceeded object count.", (void *)&(pMeta->slot_LIFO), NULL);
}
stoploss--;
@@ -520,7 +596,7 @@
}
static MALLOC_INLINE size_t
-__nano_vet_and_size_inner(nanozone_t *nanozone, const void *ptr, boolean_t inner)
+__nano_vet_and_size(nanozone_t *nanozone, const void *ptr)
{
// Extracts the size of the block in bytes. Checks for a plausible ptr.
nano_blk_addr_t p; // the compiler holds this in a register
@@ -528,15 +604,15 @@
p.addr = (uint64_t)ptr; // Begin the dissection of ptr
- if (NANOZONE_SIGNATURE != p.fields.nano_signature) {
+ if (nanozone->our_signature != p.fields.nano_signature) {
return 0;
}
- if (nano_common_max_magazines <= p.fields.nano_mag_index) {
+ if (nanozone->phys_ncpus <= p.fields.nano_mag_index) {
return 0;
}
- if (!inner && p.fields.nano_offset & NANO_QUANTA_MASK) { // stray low-order bits?
+ if (p.fields.nano_offset & NANO_QUANTA_MASK) { // stray low-order bits?
return 0;
}
@@ -544,31 +620,10 @@
if ((void *)(pMeta->slot_bump_addr) <= ptr) {
return 0; // Beyond what's ever been allocated!
}
- if (!inner && ((p.fields.nano_offset % pMeta->slot_bytes) != 0)) {
+ if ((p.fields.nano_offset % pMeta->slot_bytes) != 0) {
return 0; // Not an exact multiple of the block size for this slot
}
return pMeta->slot_bytes;
-}
-
-
-static MALLOC_INLINE size_t
-__nano_vet_and_size(nanozone_t *nanozone, const void *ptr)
-{
- return __nano_vet_and_size_inner(nanozone, ptr, false);
-}
-
-static MALLOC_ALWAYS_INLINE boolean_t
-_nano_block_has_canary_value(nanozone_t *nanozone, const void *ptr)
-{
- return (((chained_block_t)ptr)->double_free_guard ^ nanozone->cookie)
- == (uintptr_t)ptr;
-}
-
-static MALLOC_ALWAYS_INLINE void
-_nano_block_set_canary_value(nanozone_t *nanozone, const void *ptr)
-{
- ((chained_block_t)ptr)->double_free_guard =
- ((uintptr_t)ptr) ^ nanozone->cookie;
}
static MALLOC_INLINE size_t
@@ -582,7 +637,7 @@
// We have the invariant: If ptr is on a free list, then ptr->double_free_guard is the canary.
// So if ptr->double_free_guard is NOT the canary, then ptr is not on a free list, hence is live.
- if (!_nano_block_has_canary_value(nanozone, ptr)) {
+ if ((((chained_block_t)ptr)->double_free_guard ^ nanozone->cookie) != 0xBADDC0DEDEADBEADULL) {
return size; // Common case: not on a free list, hence live. Return its size.
} else {
// confirm that ptr is live despite ptr->double_free_guard having the canary value
@@ -604,7 +659,7 @@
}
// ptr was just dequed from a free list, so ptr->double_free_guard must have the canary value.
- if (_nano_block_has_canary_value(nanozone, ptr)) {
+ if ((((chained_block_t)ptr)->double_free_guard ^ nanozone->cookie) == 0xBADDC0DEDEADBEADULL) {
return size; // return the size of this well formed free block.
} else {
return 0; // Broken invariant: If ptr is on a free list, then ptr->double_free_guard is the canary. (likely use after free)
@@ -619,74 +674,58 @@
void *ptr;
size_t slot_key;
size_t slot_bytes = segregated_size_to_fit(nanozone, size, &slot_key); // Note slot_key is set here
- mag_index_t mag_index = nano_mag_index(nanozone);
+ unsigned int mag_index = NANO_MAG_INDEX(nanozone);
nano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);
ptr = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next));
if (ptr) {
- unsigned debug_flags = nanozone->debug_flags;
#if NANO_FREE_DEQUEUE_DILIGENCE
size_t gotSize;
nano_blk_addr_t p; // the compiler holds this in a register
p.addr = (uint64_t)ptr; // Begin the dissection of ptr
- if (NANOZONE_SIGNATURE != p.fields.nano_signature) {
- malloc_zone_error(debug_flags, true,
- "Invalid signature for pointer %p dequeued from free list\n",
- ptr);
+ if (nanozone->our_signature != p.fields.nano_signature) {
+ nanozone_error(nanozone, 1, "Invalid signature for pointer dequeued from free list", ptr, NULL);
}
if (mag_index != p.fields.nano_mag_index) {
- malloc_zone_error(debug_flags, true,
- "Mismatched magazine for pointer %p dequeued from free list\n",
- ptr);
+ nanozone_error(nanozone, 1, "Mismatched magazine for pointer dequeued from free list", ptr, NULL);
}
gotSize = _nano_vet_and_size_of_free(nanozone, ptr);
if (0 == gotSize) {
- malloc_zone_error(debug_flags, true,
- "Invalid pointer %p dequeued from free list\n", ptr);
+ nanozone_error(nanozone, 1, "Invalid pointer dequeued from free list", ptr, NULL);
}
if (gotSize != slot_bytes) {
- malloc_zone_error(debug_flags, true,
- "Mismatched size for pointer %p dequeued from free list\n",
- ptr);
- }
-
- if (!_nano_block_has_canary_value(nanozone, ptr)) {
- malloc_zone_error(debug_flags, true,
- "Heap corruption detected, free list canary is damaged for %p\n"
- "*** Incorrect guard value: %lu\n", ptr,
- ((chained_block_t)ptr)->double_free_guard);
- }
-
+ nanozone_error(nanozone, 1, "Mismatched size for pointer dequeued from free list", ptr, NULL);
+ }
+
+ if ((((chained_block_t)ptr)->double_free_guard ^ nanozone->cookie) != 0xBADDC0DEDEADBEADULL) {
+ nanozone_error(nanozone, 1, "Heap corruption detected, free list canary is damaged", ptr, NULL);
+ }
#if defined(DEBUG)
void *next = (void *)(((chained_block_t)ptr)->next);
if (next) {
p.addr = (uint64_t)next; // Begin the dissection of next
- if (NANOZONE_SIGNATURE != p.fields.nano_signature) {
- malloc_zone_error(debug_flags, true,
- "Invalid next signature for pointer %p dequeued from free "
- "list, next = %p\n", ptr, "next");
+ if (nanozone->our_signature != p.fields.nano_signature) {
+ nanozone_error(nanozone, 1, "Invalid next signature for pointer dequeued from free list (showing ptr, next)", ptr,
+ ", %p", next);
}
if (mag_index != p.fields.nano_mag_index) {
- malloc_zone_error(debug_flags, true,
- "Mismatched next magazine for pointer %p dequeued from "
- "free list, next = %p\n", ptr, next);
+ nanozone_error(nanozone, 1, "Mismatched next magazine for pointer dequeued from free list (showing ptr, next)", ptr,
+ ", %p", next);
}
gotSize = _nano_vet_and_size_of_free(nanozone, next);
if (0 == gotSize) {
- malloc_zone_error(debug_flags, true,
- "Invalid next for pointer %p dequeued from free list, "
- "next = %p\n", ptr, next);
+ nanozone_error(
+ nanozone, 1, "Invalid next for pointer dequeued from free list (showing ptr, next)", ptr, ", %p", next);
}
if (gotSize != slot_bytes) {
- malloc_zone_error(debug_flags, true,
- "Mismatched next size for pointer %p dequeued from free "
- "list, next = %p\n", ptr, next);
+ nanozone_error(nanozone, 1, "Mismatched next size for pointer dequeued from free list (showing ptr, next)", ptr,
+ ", %p", next);
}
}
#endif /* DEBUG */
@@ -747,14 +786,13 @@
if (do_scribble) {
(void)memset(ptr, SCRABBLE_BYTE, trusted_size);
}
- _nano_block_set_canary_value(nanozone, ptr);
+ ((chained_block_t)ptr)->double_free_guard = (0xBADDC0DEDEADBEADULL ^ nanozone->cookie);
p.addr = (uint64_t)ptr; // place ptr on the dissecting table
pMeta = &(nanozone->meta_data[p.fields.nano_mag_index][p.fields.nano_slot]);
OSAtomicEnqueue(&(pMeta->slot_LIFO), ptr, offsetof(struct chained_block_s, next));
} else {
- malloc_zone_error(nanozone->debug_flags, true,
- "Freeing unallocated pointer %p\n", ptr);
+ nanozone_error(nanozone, 1, "Freeing unallocated pointer", ptr, NULL);
}
}
@@ -785,8 +823,7 @@
old_size = _nano_vet_and_size_of_live(nanozone, ptr);
if (!old_size) {
- malloc_zone_error(nanozone->debug_flags, true,
- "pointer %p being reallocated was not allocated\n", ptr);
+ nanozone_error(nanozone, 1, "pointer being reallocated was not allocated", ptr, NULL);
return NULL;
}
@@ -822,8 +859,7 @@
_nano_destroy(nanozone_t *nanozone)
{
/* Now destroy the separate nanozone region */
- nano_common_deallocate_pages((void *)nanozone, NANOZONE_PAGED_SIZE,
- nanozone->debug_flags);
+ nano_deallocate_pages(nanozone, (void *)nanozone, NANOZONE_PAGED_SIZE, 0);
}
/****************** nanozone dispatch **********************/
@@ -876,10 +912,18 @@
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
- size_t total_bytes;
-
- if (calloc_get_size(num_items, size, 0, &total_bytes)) {
- return NULL;
+ size_t total_bytes = num_items * size;
+
+ // Check for overflow of integer multiplication
+ if (num_items > 1) {
+ /* size_t is uint64_t */
+ if ((num_items | size) & 0xffffffff00000000ul) {
+ // num_items or size equals or exceeds sqrt(2^64) == 2^32, appeal to wider arithmetic
+ __uint128_t product = ((__uint128_t)num_items) * ((__uint128_t)size);
+ if ((uint64_t)(product >> 64)) { // compiles to test on upper register of register pair
+ return NULL;
+ }
+ }
}
if (total_bytes <= NANO_MAX_SIZE) {
@@ -917,13 +961,12 @@
nano_blk_addr_t p; // happily, the compiler holds this in a register
p.addr = (uint64_t)ptr; // place ptr on the dissecting table
- if (NANOZONE_SIGNATURE == p.fields.nano_signature) {
+ if (nanozone->our_signature == p.fields.nano_signature) {
if (size == ((p.fields.nano_slot + 1) << SHIFT_NANO_QUANTUM)) { // "Trust but verify."
_nano_free_trusted_size_check_scribble(nanozone, ptr, size, do_scribble);
return;
} else {
- malloc_zone_error(nanozone->debug_flags, true,
- "Freeing pointer %p whose size was misdeclared\n", ptr);
+ nanozone_error(nanozone, 1, "Freeing pointer whose size was misdeclared", ptr, NULL);
}
} else {
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
@@ -1022,7 +1065,7 @@
p.addr = (uint64_t)ptr; // place ptr on the dissecting table
- if (NANOZONE_SIGNATURE == p.fields.nano_signature) { // Our signature?
+ if (nanozone->our_signature == p.fields.nano_signature) { // Our signature?
return _nano_size(nanozone, ptr);
} else {
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
@@ -1202,34 +1245,13 @@
return zone->memalign(zone, alignment, size);
}
-static boolean_t
-nano_claimed_address(nanozone_t *nanozone, void *ptr)
-{
- nano_blk_addr_t p;
- p.addr = (uint64_t)ptr;
- if (NANOZONE_SIGNATURE != p.fields.nano_signature) {
- // Not a nano address - let the helper zone handle it.
- malloc_zone_t *helper_zone = nanozone->helper_zone;
- return malloc_zone_claimed_address(helper_zone, ptr);
- }
- return __nano_vet_and_size_inner(nanozone, ptr, true) != 0;
-}
-
-static boolean_t
-nano_forked_claimed_address(struct _malloc_zone_t *zone, void *ptr)
-{
- // This does not operate after fork - default to true to avoid
- // false negatives.
- return true;
-}
-
static size_t
nano_try_madvise(nanozone_t *nanozone, size_t goal)
{
unsigned int mag_index, slot_key;
size_t bytes_toward_goal = 0;
- for (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {
+ for (mag_index = 0; mag_index < nanozone->phys_ncpus; mag_index++) {
nano_blk_addr_t p;
// Establish p as base address for band 0, slot 0, offset 0
@@ -1241,7 +1263,7 @@
for (slot_key = 0; slot_key < SLOT_KEY_LIMIT; p.addr += SLOT_IN_BAND_SIZE, // Advance to next slot base
slot_key++) {
- // malloc_report(ASL_LEVEL_WARNING,"nano_try_madvise examining slot base %p\n", p.addr);
+ // _malloc_printf(ASL_LEVEL_WARNING,"nano_try_madvise examining slot base %p\n", p.addr);
nano_meta_admin_t pMeta = &(nanozone->meta_data[mag_index][slot_key]);
uintptr_t slot_bump_addr = pMeta->slot_bump_addr; // capture this volatile pointer
size_t slot_objects_mapped = pMeta->slot_objects_mapped; // capture this volatile count
@@ -1258,16 +1280,16 @@
log_page_count = 1 + MAX(0, log_page_count);
bitarray_t page_bitarray = bitarray_create(log_page_count);
- // malloc_report(ASL_LEVEL_WARNING,"slot_bitarray: %db page_bitarray: %db\n", bitarray_size(log_size),
+ // _malloc_printf(ASL_LEVEL_WARNING,"slot_bitarray: %db page_bitarray: %db\n", bitarray_size(log_size),
// bitarray_size(log_page_count));
if (!slot_bitarray) {
- malloc_report(ASL_LEVEL_ERR, "bitarray_create(%d) in nano_try_madvise returned errno=%d.\n", log_size, errno);
+ malloc_printf("bitarray_create(%d) in nano_try_madvise returned errno=%d.", log_size, errno);
free(page_bitarray);
return bytes_toward_goal;
}
if (!page_bitarray) {
- malloc_report(ASL_LEVEL_ERR, "bitarray_create(%d) in nano_try_madvise returned errno=%d.\n", log_page_count, errno);
+ malloc_printf("bitarray_create(%d) in nano_try_madvise returned errno=%d.", log_page_count, errno);
free(slot_bitarray);
return bytes_toward_goal;
}
@@ -1276,7 +1298,7 @@
unsigned stoploss = (unsigned)slot_objects_mapped;
while ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {
if (0 == stoploss) {
- malloc_report(ASL_LEVEL_ERR, "Free list walk in nano_try_madvise exceeded object count.\n");
+ malloc_printf("Free list walk in nano_try_madvise exceeded object count.");
break;
}
stoploss--;
@@ -1340,7 +1362,7 @@
q.addr = slot_bump_addr - slot_bytes;
pgnum = ((((unsigned)q.fields.nano_band) << NANO_OFFSET_BITS) | ((unsigned)q.fields.nano_offset)) >> vm_kernel_page_shift;
- // malloc_report(ASL_LEVEL_WARNING,"Examining %d pages. Slot base %p.\n", pgnum - pgstart + 1, p.addr);
+ // _malloc_printf(ASL_LEVEL_WARNING,"Examining %d pages. Slot base %p.\n", pgnum - pgstart + 1, p.addr);
if (pMeta->slot_madvised_pages) {
if (pMeta->slot_madvised_log_page_count < log_page_count) {
@@ -1374,7 +1396,7 @@
if (num_advised) {
chained_block_t new_head = NULL, new_tail = NULL;
- // malloc_report(ASL_LEVEL_WARNING,"Constructing residual free list starting at %p num_advised %d\n", head,
+ // _malloc_printf(ASL_LEVEL_WARNING,"Constructing residual free list starting at %p num_advised %d\n", head,
// num_advised);
t = head;
while (t) {
@@ -1420,7 +1442,7 @@
(uintptr_t)new_tail - (uintptr_t)new_head + offsetof(struct chained_block_s, next));
}
} else {
- // malloc_report(ASL_LEVEL_WARNING,"Reinstating free list since no pages were madvised (%d).\n", num_advised);
+ // _malloc_printf(ASL_LEVEL_WARNING,"Reinstating free list since no pages were madvised (%d).\n", num_advised);
if (head) {
OSAtomicEnqueue(&(pMeta->slot_LIFO), head,
(uintptr_t)tail - (uintptr_t)head + offsetof(struct chained_block_s, next));
@@ -1432,7 +1454,7 @@
q = p;
q.fields.nano_band = (i << vm_kernel_page_shift) >> NANO_OFFSET_BITS;
q.fields.nano_offset = (i << vm_kernel_page_shift) & ((1 << NANO_OFFSET_BITS) - 1);
- // malloc_report(ASL_LEVEL_WARNING,"Entire page non-live: %d. Slot base %p, madvising %p\n", i, p.addr,
+ // _malloc_printf(ASL_LEVEL_WARNING,"Entire page non-live: %d. Slot base %p, madvising %p\n", i, p.addr,
// q.addr);
if (nanozone->debug_flags & MALLOC_DO_SCRIBBLE) {
@@ -1472,18 +1494,17 @@
static size_t
nano_pressure_relief(nanozone_t *nanozone, size_t goal)
{
- MAGMALLOC_PRESSURERELIEFBEGIN((void *)nanozone, nanozone->basic_zone.zone_name, (int)goal);
- MALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_START, (uint64_t)nanozone, goal, 0, 0);
-
- size_t total = nano_try_madvise(nanozone, goal);
-
- MAGMALLOC_PRESSURERELIEFEND((void *)nanozone, nanozone->basic_zone.zone_name, (int)goal, (int)total);
- MALLOC_TRACE(TRACE_nano_memory_pressure | DBG_FUNC_END, (uint64_t)nanozone, goal, total, 0);
-
- return total;
+ return nano_try_madvise(nanozone, goal);
}
/**************** introspection methods *********************/
+
+static kern_return_t
+nanozone_default_reader(task_t task, vm_address_t address, vm_size_t size, void **ptr)
+{
+ *ptr = (void *)address;
+ return 0;
+}
static kern_return_t
nano_ptr_in_use_enumerator(task_t task,
@@ -1495,19 +1516,17 @@
{
nanozone_t *nanozone;
kern_return_t err;
- struct nanozone_s zone_copy;
if (!reader) {
- reader = nano_common_default_reader;
+ reader = nanozone_default_reader;
}
err = reader(task, zone_address, sizeof(nanozone_t), (void **)&nanozone);
if (err) {
return err;
}
- memcpy(&zone_copy, nanozone, sizeof(zone_copy));
-
- err = segregated_in_use_enumerator(task, context, type_mask, &zone_copy, reader, recorder);
+
+ err = segregated_in_use_enumerator(task, context, type_mask, nanozone, reader, recorder);
return err;
}
@@ -1515,7 +1534,7 @@
nano_good_size(nanozone_t *nanozone, size_t size)
{
if (size <= NANO_MAX_SIZE) {
- return _nano_common_good_size(size);
+ return _nano_good_size(nanozone, size);
} else {
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
return zone->introspect->good_size(zone, size);
@@ -1537,7 +1556,7 @@
nanozone_check(nanozone_t *nanozone)
{
if ((++nanozone_check_counter % 10000) == 0) {
- malloc_report(ASL_LEVEL_NOTICE, "at nanozone_check counter=%d\n", nanozone_check_counter);
+ _malloc_printf(ASL_LEVEL_NOTICE, "at nanozone_check counter=%d\n", nanozone_check_counter);
}
if (nanozone_check_counter < nanozone_check_start) {
@@ -1560,9 +1579,7 @@
unsigned stoploss = (unsigned)pMeta->slot_objects_mapped;
while ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {
if (0 == stoploss) {
- malloc_zone_error(nanozone->debug_flags, true,
- "Free list walk in count_free exceeded object count.\n",
- (void *)&(pMeta->slot_LIFO), NULL);
+ nanozone_error(nanozone, 1, "Free list walk in count_free exceeded object count.", (void *)&(pMeta->slot_LIFO), NULL);
}
stoploss--;
@@ -1594,12 +1611,10 @@
malloc_statistics_t stats;
nano_statistics(nanozone, &stats);
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,
- "Nanozone %p: inUse=%d(%lluKB) touched=%lluKB allocated=%lluMB\n",
- nanozone, stats.blocks_in_use, (uint64_t)stats.size_in_use >> 10,
- (uint64_t)stats.max_size_in_use >> 10, (uint64_t)stats.size_allocated >> 20);
-
- for (mag_index = 0; mag_index < nano_common_max_magazines; mag_index++) {
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "Nanozone %p: inUse=%d(%dKB) touched=%dKB allocated=%dMB\n",
+ nanozone, stats.blocks_in_use, stats.size_in_use >> 10, stats.max_size_in_use >> 10, stats.size_allocated >> 20);
+
+ for (mag_index = 0; mag_index < nanozone->phys_ncpus; mag_index++) {
nano_blk_addr_t p;
// Establish p as base address for band 0, slot 0, offset 0
@@ -1616,7 +1631,7 @@
size_t slot_objects_mapped = pMeta->slot_objects_mapped; // capture this volatile count
if (0 == slot_objects_mapped) { // Nothing allocated in this magazine for this slot?
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "Magazine %2d(%3d) Unrealized\n", mag_index,
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "Magazine %2d(%3d) Unrealized\n", mag_index,
(slot_key + 1) << SHIFT_NANO_QUANTUM);
continue;
}
@@ -1630,10 +1645,10 @@
size_t size_in_use = ((slot_key + 1) << SHIFT_NANO_QUANTUM) * blocks_in_use;
size_t size_allocated = ((offset / BAND_SIZE) + 1) * SLOT_IN_BAND_SIZE;
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX,
- "Magazine %2d(%3d) [%p, %3lluKB] \t Allocations in use=%4d \t Bytes in use=%llub \t Untouched=%lluKB\n", mag_index,
- (slot_key + 1) << SHIFT_NANO_QUANTUM, (void *)p.addr, (uint64_t)(size_allocated >> 10), blocks_in_use, (uint64_t)size_in_use,
- (uint64_t)((size_allocated - size_hiwater) >> 10));
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX,
+ "Magazine %2d(%3d) [%p, %3dKB] \t Allocations in use=%4d \t Bytes in use=%db \t Untouched=%dKB\n", mag_index,
+ (slot_key + 1) << SHIFT_NANO_QUANTUM, p, (size_allocated >> 10), blocks_in_use, size_in_use,
+ (size_allocated - size_hiwater) >> 10);
if (!verbose) {
continue;
@@ -1643,7 +1658,7 @@
bitarray_t slot_bitarray = bitarray_create(log_size);
if (!slot_bitarray) {
- malloc_report(ASL_LEVEL_ERR, "bitarray_create(%d) in nano_print returned errno=%d.\n", log_size, errno);
+ malloc_printf("bitarray_create(%d) in nano_print returned errno=%d.", log_size, errno);
return;
}
@@ -1651,7 +1666,7 @@
unsigned stoploss = (unsigned)slot_objects_mapped;
while ((t = OSAtomicDequeue(&(pMeta->slot_LIFO), offsetof(struct chained_block_s, next)))) {
if (0 == stoploss) {
- malloc_report(ASL_LEVEL_ERR, "Free list walk in nano_print exceeded object count.\n");
+ malloc_printf("Free list walk in nano_print exceeded object count.");
break;
}
stoploss--;
@@ -1688,17 +1703,17 @@
vm_kernel_page_shift;
if (i < pMeta->slot_objects_skipped) {
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "_");
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "_");
} else if (bitarray_get(slot_bitarray, log_size, i)) {
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "F");
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "F");
} else if (pMeta->slot_madvised_pages && (pgnum < (1 << pMeta->slot_madvised_log_page_count)) &&
bitarray_get(pMeta->slot_madvised_pages, pMeta->slot_madvised_log_page_count, (index_t)pgnum)) {
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "M");
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "M");
} else {
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, ".");
- }
- }
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "\n");
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, ".");
+ }
+ }
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "\n");
free(slot_bitarray);
@@ -1723,7 +1738,7 @@
{
int i;
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
_malloc_lock_lock(&nanozone->band_resupply_lock[i]);
}
}
@@ -1733,7 +1748,7 @@
{
int i;
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
_malloc_lock_unlock(&nanozone->band_resupply_lock[i]);
}
}
@@ -1743,7 +1758,7 @@
{
int i;
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
_malloc_lock_init(&nanozone->band_resupply_lock[i]);
}
}
@@ -1755,7 +1770,7 @@
bzero(stats, sizeof(*stats));
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
nano_blk_addr_t p;
// Establish p as base address for slot 0 in this CPU magazine
@@ -1796,7 +1811,7 @@
{
int i;
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
if (_malloc_lock_trylock(&nanozone->band_resupply_lock[i])) {
_malloc_lock_unlock(&nanozone->band_resupply_lock[i]);
return TRUE;
@@ -1845,34 +1860,39 @@
nanozone->basic_zone.introspect = (struct malloc_introspection_t *)&nano_introspect; /* Unchanged. */
nanozone->basic_zone.memalign = (void *)nano_memalign; /* Unchanged. */
nanozone->basic_zone.free_definite_size = (void *)nano_forked_free_definite_size;
- nanozone->basic_zone.claimed_address = nano_forked_claimed_address;
mprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ);
}
malloc_zone_t *
-nano_create_zone(malloc_zone_t *helper_zone, unsigned debug_flags)
+create_nano_zone(size_t initial_size, malloc_zone_t *helper_zone, unsigned debug_flags)
{
nanozone_t *nanozone;
int i, j;
- /* Note: It is important that nano_create_zone resets _malloc_engaged_nano
+ /* Note: It is important that create_nano_zone clears _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.
*/
- MALLOC_ASSERT(_malloc_engaged_nano == NANO_V1);
+ if (!_malloc_engaged_nano) {
+ return NULL;
+ }
+
+ if (_COMM_PAGE_VERSION_REQD > (*((uint16_t *)_COMM_PAGE_VERSION))) {
+ MALLOC_PRINTF_FATAL_ERROR((*((uint16_t *)_COMM_PAGE_VERSION)), "comm page version mismatch");
+ }
/* get memory for the zone. */
- nanozone = nano_common_allocate_based_pages(NANOZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC, 0);
+ nanozone = nano_allocate_pages(NULL, NANOZONE_PAGED_SIZE, 0, 0, VM_MEMORY_MALLOC);
if (!nanozone) {
- _malloc_engaged_nano = NANO_NONE;
+ _malloc_engaged_nano = false;
return NULL;
}
/* set up the basic_zone portion of the nanozone structure */
- nanozone->basic_zone.version = 10;
+ nanozone->basic_zone.version = 9;
nanozone->basic_zone.size = (void *)nano_size;
nanozone->basic_zone.malloc = (debug_flags & MALLOC_DO_SCRIBBLE) ? (void *)nano_malloc_scribble : (void *)nano_malloc;
nanozone->basic_zone.calloc = (void *)nano_calloc;
@@ -1888,31 +1908,48 @@
: (void *)nano_free_definite_size;
nanozone->basic_zone.pressure_relief = (void *)nano_pressure_relief;
- nanozone->basic_zone.claimed_address = (void *)nano_claimed_address;
nanozone->basic_zone.reserved1 = 0; /* Set to zero once and for all as required by CFAllocator. */
nanozone->basic_zone.reserved2 = 0; /* Set to zero once and for all as required by CFAllocator. */
mprotect(nanozone, sizeof(nanozone->basic_zone), PROT_READ); /* Prevent overwriting the function pointers in basic_zone. */
- /* Nano zone does not support MALLOC_ADD_GUARD_PAGES. */
- if (debug_flags & MALLOC_ADD_GUARD_PAGES) {
- malloc_report(ASL_LEVEL_INFO, "nano zone does not support guard pages\n");
- debug_flags &= ~MALLOC_ADD_GUARD_PAGES;
- }
-
/* set up the remainder of the nanozone structure */
nanozone->debug_flags = debug_flags;
-
- if (phys_ncpus > sizeof(nanozone->core_mapped_size) /
+ nanozone->our_signature = NANOZONE_SIGNATURE;
+
+/* Query the number of configured processors. */
+ nanozone->phys_ncpus = *(uint8_t *)(uintptr_t)_COMM_PAGE_PHYSICAL_CPUS;
+ nanozone->logical_ncpus = *(uint8_t *)(uintptr_t)_COMM_PAGE_LOGICAL_CPUS;
+
+ if (nanozone->phys_ncpus > sizeof(nanozone->core_mapped_size) /
sizeof(nanozone->core_mapped_size[0])) {
- MALLOC_REPORT_FATAL_ERROR(phys_ncpus,
+ MALLOC_PRINTF_FATAL_ERROR(nanozone->phys_ncpus,
"nanozone abandoned because NCPUS > max magazines.\n");
+ }
+
+ if (0 != (nanozone->logical_ncpus % nanozone->phys_ncpus)) {
+ MALLOC_PRINTF_FATAL_ERROR(nanozone->logical_ncpus % nanozone->phys_ncpus,
+ "logical_ncpus % phys_ncpus != 0");
+ }
+
+ switch (nanozone->logical_ncpus / nanozone->phys_ncpus) {
+ case 1:
+ nanozone->hyper_shift = 0;
+ break;
+ case 2:
+ nanozone->hyper_shift = 1;
+ break;
+ case 4:
+ nanozone->hyper_shift = 2;
+ break;
+ default:
+ MALLOC_PRINTF_FATAL_ERROR(nanozone->logical_ncpus / nanozone->phys_ncpus, "logical_ncpus / phys_ncpus not 1, 2, or 4");
}
/* Initialize slot queue heads and resupply locks. */
OSQueueHead q0 = OS_ATOMIC_QUEUE_INIT;
- for (i = 0; i < nano_common_max_magazines; ++i) {
+ for (i = 0; i < nanozone->phys_ncpus; ++i) {
_malloc_lock_init(&nanozone->band_resupply_lock[i]);
for (j = 0; j < NANO_SLOT_SIZE; ++j) {
@@ -1921,36 +1958,58 @@
}
/* Initialize the security token. */
+ if (0 == _dyld_get_image_slide((const struct mach_header *)_NSGetMachExecuteHeader())) {
+ // zero slide when ASLR has been disabled by boot-arg. Eliminate cloaking.
+ malloc_entropy[0] = 0;
+ malloc_entropy[1] = 0;
+ }
nanozone->cookie = (uintptr_t)malloc_entropy[0] & 0x0000ffffffff0000ULL; // scramble central 32bits with this cookie
+ /* Nano zone does not support MALLOC_ADD_GUARD_PAGES. */
+ if (nanozone->debug_flags & MALLOC_ADD_GUARD_PAGES) {
+ _malloc_printf(ASL_LEVEL_INFO, "nano zone does not support guard pages\n");
+ nanozone->debug_flags &= ~MALLOC_ADD_GUARD_PAGES;
+ }
+
nanozone->helper_zone = helper_zone;
return (malloc_zone_t *)nanozone;
}
+boolean_t _malloc_engaged_nano;
+
void
-nano_init(const char *envp[], const char *apple[],
- const char *bootargs MALLOC_UNUSED)
-{
+nano_init(const char *envp[], const char *apple[])
+{
+ const char *flag = _simple_getenv(apple, "MallocNanoZone");
+ if (flag && flag[0] == '1') {
+ _malloc_engaged_nano = 1;
+ }
+#if CONFIG_NANO_SMALLMEM_DYNAMIC_DISABLE_35305995
+ // Disable nano malloc on <=1gb configurations rdar://problem/35305995
+ uint64_t memsize = platform_hw_memsize();
+ if (memsize <= (1ull << 30)) {
+ _malloc_engaged_nano = 0;
+ }
+#endif // CONFIG_NANO_SMALLMEM_DYNAMIC_DISABLE_35305995
+ /* Explicit overrides from the environment */
+ flag = _simple_getenv(envp, "MallocNanoZone");
+ if (flag && flag[0] == '1') {
+ _malloc_engaged_nano = 1;
+ } else if (flag && flag[0] == '0') {
+ _malloc_engaged_nano = 0;
+ }
#if NANO_PREALLOCATE_BAND_VM
// Unconditionally preallocate the VA space set aside for nano malloc to
// reserve it in all configurations. rdar://problem/33392283
boolean_t preallocated = nano_preallocate_band_vm();
- if (!preallocated) {
- malloc_report(ASL_LEVEL_NOTICE, "nano zone abandoned due to inability to preallocate reserved vm space.\n");
- _malloc_engaged_nano = NANO_NONE;
+ if (!preallocated && _malloc_engaged_nano) {
+ _malloc_printf(ASL_LEVEL_NOTICE, "nano zone abandoned due to inability to preallocate reserved vm space.\n");
+ _malloc_engaged_nano = 0;
}
#endif
}
-// Second phase of initialization, called during _malloc_initialize(), after
-// environment variables have been read and processed.
-void
-nano_configure()
-{
- // Nothing to do.
-}
-
#endif // CONFIG_NANOZONE
/* vim: set noet:ts=4:sw=4:cindent: */