Loading...
--- libmalloc/libmalloc-116/src/nano_malloc.c
+++ libmalloc/libmalloc-116.30.3/src/nano_malloc.c
@@ -566,6 +566,10 @@
 
 	p.addr = (uint64_t)ptr; // Begin the dissection of ptr
 
+	if (nanozone->our_signature != p.fields.nano_signature) {
+		return 0;
+	}
+
 	if (nanozone->phys_ncpus <= p.fields.nano_mag_index) {
 		return 0;
 	}
@@ -952,14 +956,19 @@
 __nano_free(nanozone_t *nanozone, void *ptr, boolean_t do_scribble)
 {
 	MALLOC_TRACE(TRACE_nano_free, (uintptr_t)nanozone, (uintptr_t)ptr, do_scribble, 0);
-	nano_blk_addr_t p; // happily, the compiler holds this in a register
 
 	if (!ptr) {
 		return; // Protect against malloc_zone_free() passing NULL.
 	}
-	p.addr = (uint64_t)ptr; // place ptr on the dissecting table
-	if (nanozone->our_signature == p.fields.nano_signature) {
-		_nano_free_check_scribble(nanozone, ptr, do_scribble);
+
+	// <rdar://problem/26481467> exhausting a slot may result in a pointer with
+	// the nanozone prefix being given to nano_free via malloc_zone_free. Calling
+	// vet_and_size here, instead of in _nano_free_check_scribble means we can
+	// early-out into the helper_zone if it turns out nano does not own this ptr.
+	size_t sz = _nano_vet_and_size_of_live(nanozone, ptr);
+
+	if (sz) {
+		_nano_free_trusted_size_check_scribble(nanozone, ptr, sz, do_scribble);
 		return;
 	} else {
 		malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);