Loading...
--- libmalloc/libmalloc-166.251.2/src/magazine_large.c
+++ libmalloc/libmalloc-140.40.1/src/magazine_large.c
@@ -38,48 +38,11 @@
}
}
- malloc_report(MALLOC_REPORT_NOLOG | MALLOC_REPORT_NOPREFIX, "%s\n", _simple_string(b));
+ _malloc_printf(MALLOC_PRINTF_NOLOG | MALLOC_PRINTF_NOPREFIX, "%s\n", _simple_string(b));
_simple_sfree(b);
}
}
#endif
-
-/*
- * Scan the hash ring looking for an entry containing a given pointer.
- */
-static large_entry_t *
-large_entry_containing_pointer_no_lock(szone_t *szone, const void *ptr)
-{
- // result only valid with lock held
- unsigned num_large_entries = szone->num_large_entries;
- unsigned hash_index;
- unsigned index;
- large_entry_t *range;
-
- if (!num_large_entries) {
- return NULL;
- }
-
- hash_index = ((uintptr_t)ptr >> vm_page_quanta_shift) % num_large_entries;
- index = hash_index;
-
- do {
- range = szone->large_entries + index;
- if (range->address == (vm_address_t)ptr) {
- return range;
- } else if ((vm_address_t)ptr >= range->address
- && (vm_address_t)ptr < range->address + range->size) {
- return range;
- }
-
- // Since we may be looking for an inner pointer, we might not get an
- // exact match on the address, so we need to scan further and to skip
- // over empty entries. It will usually be faster to scan backwards.
- index = index == 0 ? num_large_entries - 1 : index - 1;
- } while (index != hash_index);
-
- return NULL;
-}
/*
* Scan the hash ring looking for an entry for the given pointer.
@@ -258,7 +221,7 @@
#if DEBUG_MALLOC
if (large_entry_for_pointer_no_lock(szone, (void *)range.address)) {
- malloc_report(ASL_LEVEL_ERR, "*** freed entry %p still in use; num_large_entries=%d\n", range.address, szone->num_large_entries);
+ malloc_printf("*** freed entry %p still in use; num_large_entries=%d\n", range.address, szone->num_large_entries);
large_debug_print(szone);
szone_sleep();
}
@@ -449,11 +412,45 @@
mvm_deallocate_pages((void *)range_to_deallocate.address, range_to_deallocate.size, 0);
}
- if (cleared_requested) {
- memset(addr, 0, size);
- }
-
- return addr;
+ // Perform the madvise() outside the lock.
+ // Typically the madvise() is successful and we'll quickly return from this routine.
+ // In the unusual case of failure, reacquire the lock to unwind.
+#if TARGET_OS_EMBEDDED
+ // Ok to do this madvise on embedded because we won't call MADV_FREE_REUSABLE on a large
+ // cache block twice without MADV_FREE_REUSE in between.
+#endif
+ if (was_madvised_reusable && -1 == madvise(addr, size, MADV_FREE_REUSE)) {
+ /* -1 return: VM map entry change makes this unfit for reuse. */
+#if DEBUG_MADVISE
+ szone_error(szone->debug_flags, 0, "large_malloc madvise(..., MADV_FREE_REUSE) failed", addr, "length=%d\n", size);
+#endif
+
+ SZONE_LOCK(szone);
+ szone->num_large_objects_in_use--;
+ szone->num_bytes_in_large_objects -= large_entry.size;
+
+ // Re-acquire "entry" after interval just above where we let go the lock.
+ large_entry_t *entry = large_entry_for_pointer_no_lock(szone, addr);
+ if (NULL == entry) {
+ szone_error(szone->debug_flags, 1, "entry for pointer being discarded from death-row vanished", addr, NULL);
+ SZONE_UNLOCK(szone);
+ } else {
+ range_to_deallocate = large_entry_free_no_lock(szone, entry);
+ SZONE_UNLOCK(szone);
+
+ if (range_to_deallocate.size) {
+ // we deallocate outside the lock
+ mvm_deallocate_pages((void *)range_to_deallocate.address, range_to_deallocate.size, 0);
+ }
+ }
+ /* Fall through to allocate_pages() afresh. */
+ } else {
+ if (cleared_requested) {
+ memset(addr, 0, size);
+ }
+
+ return addr;
+ }
} else {
SZONE_UNLOCK(szone);
}
@@ -521,7 +518,7 @@
// is accommodated, matching the behavior of the previous implementation.]
while (1) { // Scan large_entry_cache starting with most recent entry
if (szone->large_entry_cache[idx].address == entry->address) {
- malloc_zone_error(szone->debug_flags, true, "pointer %p being freed already on death-row\n", ptr);
+ szone_error(szone->debug_flags, 1, "pointer being freed already on death-row", ptr, NULL);
SZONE_UNLOCK(szone);
return;
}
@@ -543,8 +540,8 @@
int state = VM_PURGABLE_NONVOLATILE; // restore to default condition
if (KERN_SUCCESS != vm_purgable_control(mach_task_self(), this_entry.address, VM_PURGABLE_SET_STATE, &state)) {
- malloc_report(ASL_LEVEL_ERR, "*** can't vm_purgable_control(..., VM_PURGABLE_SET_STATE) for large freed block at %p\n",
- (void *)this_entry.address);
+ malloc_printf("*** can't vm_purgable_control(..., VM_PURGABLE_SET_STATE) for large freed block at %p\n",
+ this_entry.address);
reusable = FALSE;
}
}
@@ -553,7 +550,7 @@
// Accomodate Leopard apps that (illegally) mprotect() their own guard pages on large malloc'd allocations
int err = mprotect((void *)(this_entry.address), this_entry.size, PROT_READ | PROT_WRITE);
if (err) {
- malloc_report(ASL_LEVEL_ERR, "*** can't reset protection for large freed block at %p\n", (void *)this_entry.address);
+ malloc_printf("*** can't reset protection for large freed block at %p\n", this_entry.address);
reusable = FALSE;
}
}
@@ -561,17 +558,20 @@
// madvise(..., MADV_REUSABLE) death-row arrivals if hoarding would exceed large_entry_cache_reserve_limit
if (should_madvise) {
// Issue madvise to avoid paging out the dirtied free()'d pages in "entry"
- MAGMALLOC_MADVFREEREGION((void *)szone, (void *)0, (void *)(this_entry.address), (int)this_entry.size); // DTrace USDT Probe
-
+ MAGMALLOC_MADVFREEREGION(
+ (void *)szone, (void *)0, (void *)(this_entry.address), (int)this_entry.size); // DTrace USDT Probe
+
+#if TARGET_OS_EMBEDDED
// Ok to do this madvise on embedded because we won't call MADV_FREE_REUSABLE on a large
// cache block twice without MADV_FREE_REUSE in between.
-
+#endif
if (-1 == madvise((void *)(this_entry.address), this_entry.size, MADV_FREE_REUSABLE)) {
/* -1 return: VM map entry change makes this unfit for reuse. */
#if DEBUG_MADVISE
- malloc_zone_error(szone->debug_flags, false,
- "free_large madvise(..., MADV_FREE_REUSABLE) failed for %p, length=%d\n",
- (void *)this_entry.address, this_entry.size);
+ szone_error(szone->debug_flags, 0,
+ "free_large madvise(..., MADV_FREE_REUSABLE) failed",
+ (void *)this_entry.address,
+ "length=%d\n", this_entry.size);
#endif
reusable = FALSE;
}
@@ -582,7 +582,7 @@
// Re-acquire "entry" after interval just above where we let go the lock.
entry = large_entry_for_pointer_no_lock(szone, ptr);
if (NULL == entry) {
- malloc_zone_error(szone->debug_flags, true, "entry for pointer %p being freed from death-row vanished\n", ptr);
+ szone_error(szone->debug_flags, 1, "entry for pointer being freed from death-row vanished", ptr, NULL);
SZONE_UNLOCK(szone);
return;
}
@@ -676,7 +676,7 @@
#if DEBUG_MALLOC
large_debug_print(szone);
#endif
- malloc_zone_error(szone->debug_flags, true, "pointer %p being freed was not allocated\n", ptr);
+ szone_error(szone->debug_flags, 1, "pointer being freed was not allocated", ptr, NULL);
SZONE_UNLOCK(szone);
return;
}
@@ -688,8 +688,8 @@
#if DEBUG_MALLOC
// FIXME: large_entry_for_pointer_no_lock() needs the lock held ...
if (large_entry_for_pointer_no_lock(szone, (void *)vm_range_to_deallocate.address)) {
- malloc_report(ASL_LEVEL_ERR, "*** invariant broken: %p still in use num_large_entries=%d\n",
- vm_range_to_deallocate.address, szone->num_large_entries);
+ malloc_printf("*** invariant broken: %p still in use num_large_entries=%d\n", vm_range_to_deallocate.address,
+ szone->num_large_entries);
large_debug_print(szone);
szone_sleep();
}
@@ -708,7 +708,7 @@
/* contract existing large entry */
large_entry_t *large_entry = large_entry_for_pointer_no_lock(szone, ptr);
if (!large_entry) {
- malloc_zone_error(szone->debug_flags, true, "large entry %p reallocated is not properly in table\n", ptr);
+ szone_error(szone->debug_flags, 1, "large entry reallocated is not properly in table", ptr, NULL);
SZONE_UNLOCK(szone);
return ptr;
}
@@ -716,21 +716,7 @@
large_entry->address = (vm_address_t)ptr;
large_entry->size = new_good_size;
szone->num_bytes_in_large_objects -= shrinkage;
- boolean_t guarded = szone->debug_flags & MALLOC_ADD_GUARD_PAGES;
SZONE_UNLOCK(szone); // we release the lock asap
-
- if (guarded) {
- // Keep the page above the new end of the allocation as the
- // postlude guard page.
- kern_return_t err;
- err = mprotect((void *)((uintptr_t)ptr + new_good_size), vm_page_quanta_size, 0);
- if (err) {
- malloc_report(ASL_LEVEL_ERR, "*** can't mvm_protect(0x0) region for new postlude guard page at %p\n",
- ptr + new_good_size);
- }
- new_good_size += vm_page_quanta_size;
- shrinkage -= vm_page_quanta_size;
- }
mvm_deallocate_pages((void *)((uintptr_t)ptr + new_good_size), shrinkage, 0);
}
@@ -766,7 +752,7 @@
/* extend existing large entry */
large_entry = large_entry_for_pointer_no_lock(szone, ptr);
if (!large_entry) {
- malloc_zone_error(szone->debug_flags, true, "large entry %p reallocated is not properly in table\n", ptr);
+ szone_error(szone->debug_flags, 1, "large entry reallocated is not properly in table", ptr, NULL);
SZONE_UNLOCK(szone);
return 0; // Bail, leaking "addr"
}
@@ -778,13 +764,3 @@
return 1;
}
-
-boolean_t
-large_claimed_address(szone_t *szone, void *ptr)
-{
- SZONE_LOCK(szone);
- boolean_t result = large_entry_containing_pointer_no_lock(szone,
- (void *)trunc_page((uintptr_t)ptr)) != NULL;
- SZONE_UNLOCK(szone);
- return result;
-}