Bug 1284677 - Change how the default OSX malloc zone is found. r?njn draft
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 08 Jul 2016 14:48:16 +0900
changeset 385328 3872debcedfa1336ea13581dc73af36a07efea95
parent 385294 038d7b021492e648483aba1f1291ad7e902d4611
child 386646 d6792109b178b08002df6d2f15d2450f3605dd41
child 387864 372d4e9405b3357cffabc2e73d4feed13ff9479a
push id22480
push userbmo:mh+mozilla@glandium.org
push dateFri, 08 Jul 2016 05:50:43 +0000
reviewersnjn
bugs1284677
milestone50.0a1
Bug 1284677 - Change how the default OSX malloc zone is found. r?njn
memory/build/replace_malloc.c
--- a/memory/build/replace_malloc.c
+++ b/memory/build/replace_malloc.c
@@ -428,19 +428,48 @@ zone_force_unlock(malloc_zone_t *zone)
 {
 }
 
 #endif
 
 static malloc_zone_t zone;
 static struct malloc_introspection_t zone_introspect;
 
+static malloc_zone_t *get_default_zone()
+{
+  malloc_zone_t **zones = NULL;
+  unsigned int num_zones = 0;
+
+  /*
+   * On OSX 10.12, malloc_default_zone returns a special zone that is not
+   * present in the list of registered zones. That zone uses a "lite zone"
+   * if one is present (apparently enabled when malloc stack logging is
+   * enabled), or the first registered zone otherwise. In practice this
+   * means unless malloc stack logging is enabled, the first registered
+   * zone is the default.
+   * So get the list of zones to get the first one, instead of relying on
+   * malloc_default_zone.
+   */
+  if (KERN_SUCCESS != malloc_get_all_zones(0, NULL, (vm_address_t**) &zones,
+                                           &num_zones)) {
+    /* Reset the value in case the failure happened after it was set. */
+    num_zones = 0;
+  }
+  if (num_zones) {
+    return zones[0];
+  }
+  return malloc_default_zone();
+}
+
+
 __attribute__((constructor)) void
 register_zone(void)
 {
+  malloc_zone_t *default_zone = get_default_zone();
+
   zone.size = (void *)zone_size;
   zone.malloc = (void *)zone_malloc;
   zone.calloc = (void *)zone_calloc;
   zone.valloc = (void *)zone_valloc;
   zone.free = (void *)zone_free;
   zone.realloc = (void *)zone_realloc;
   zone.destroy = (void *)zone_destroy;
   zone.zone_name = "replace_malloc_zone";
@@ -483,17 +512,16 @@ register_zone(void)
    * a scalable_zone.
    */
   malloc_zone_t *purgeable_zone = malloc_default_purgeable_zone();
 
   /* Register the custom zone.  At this point it won't be the default. */
   malloc_zone_register(&zone);
 
   do {
-    malloc_zone_t *default_zone = malloc_default_zone();
     /*
      * Unregister and reregister the default zone.  On OSX >= 10.6,
      * unregistering takes the last registered zone and places it at the
      * location of the specified zone.  Unregistering the default zone thus
      * makes the last registered one the default.  On OSX < 10.6,
      * unregistering shifts all registered zones.  The first registered zone
      * then becomes the default.
      */
@@ -507,11 +535,12 @@ register_zone(void)
      * unregistering shifts registered zones, this simply removes the purgeable
      * zone from the list and adds it back at the end, after the default zone.
      * On OSX >= 10.6, unregistering replaces the purgeable zone with the last
      * registered zone above, i.e the default zone. Registering it again then
      * puts it at the end, obviously after the default zone.
      */
     malloc_zone_unregister(purgeable_zone);
     malloc_zone_register(purgeable_zone);
-  } while (malloc_default_zone() != &zone);
+    default_zone = get_default_zone();
+  } while (default_zone != &zone);
 }
 #endif