[compiler-rt] 3abf3df - [Sanitizer][Darwin] Lookup dyld image header via shared cache

Julian Lettner via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 30 15:45:33 PDT 2022


Author: Julian Lettner
Date: 2022-06-30T15:45:25-07:00
New Revision: 3abf3df08adb532af318dd0b39c6bff17c81e9b0

URL: https://github.com/llvm/llvm-project/commit/3abf3df08adb532af318dd0b39c6bff17c81e9b0
DIFF: https://github.com/llvm/llvm-project/commit/3abf3df08adb532af318dd0b39c6bff17c81e9b0.diff

LOG: [Sanitizer][Darwin] Lookup dyld image header via shared cache

On macOS 13+, dyld itself has moved into the shared cache.  Looking it
up via vm_region_recurse_64() now causes spins/hangs/crashes.  We use a
different set of dyld APIs to find the image header in the shared cache.

rdar://92131949

Differential Revision: https://reviews.llvm.org/D128936

Added: 
    

Modified: 
    compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
index 01d7957763d2d..66f4935bb62d7 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_procmaps_mac.cpp
@@ -136,13 +136,19 @@ void MemoryMappingLayout::LoadFromCache() {
   // No-op on Mac for now.
 }
 
+static bool IsDyldHdr(const mach_header *hdr) {
+  return (hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
+         hdr->filetype == MH_DYLINKER;
+}
+
 // _dyld_get_image_header() and related APIs don't report dyld itself.
 // We work around this by manually recursing through the memory map
 // until we hit a Mach header matching dyld instead. These recurse
 // calls are expensive, but the first memory map generation occurs
 // early in the process, when dyld is one of the only images loaded,
-// so it will be hit after only a few iterations.
-static mach_header *get_dyld_image_header() {
+// so it will be hit after only a few iterations.  These assumptions don't hold
+// on macOS 13+ anymore (dyld itself has moved into the shared cache).
+static mach_header *GetDyldImageHeaderViaVMRegion() {
   vm_address_t address = 0;
 
   while (true) {
@@ -157,8 +163,7 @@ static mach_header *get_dyld_image_header() {
 
     if (size >= sizeof(mach_header) && info.protection & kProtectionRead) {
       mach_header *hdr = (mach_header *)address;
-      if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
-          hdr->filetype == MH_DYLINKER) {
+      if (IsDyldHdr(hdr)) {
         return hdr;
       }
     }
@@ -166,8 +171,69 @@ static mach_header *get_dyld_image_header() {
   }
 }
 
+extern "C" {
+struct dyld_shared_cache_dylib_text_info {
+  uint64_t version;  // current version 2
+  // following fields all exist in version 1
+  uint64_t loadAddressUnslid;
+  uint64_t textSegmentSize;
+  uuid_t dylibUuid;
+  const char *path;  // pointer invalid at end of iterations
+  // following fields all exist in version 2
+  uint64_t textSegmentOffset;  // offset from start of cache
+};
+typedef struct dyld_shared_cache_dylib_text_info
+    dyld_shared_cache_dylib_text_info;
+
+extern bool _dyld_get_shared_cache_uuid(uuid_t uuid);
+extern const void *_dyld_get_shared_cache_range(size_t *length);
+extern int dyld_shared_cache_iterate_text(
+    const uuid_t cacheUuid,
+    void (^callback)(const dyld_shared_cache_dylib_text_info *info));
+}  // extern "C"
+
+static mach_header *GetDyldImageHeaderViaSharedCache() {
+  uuid_t uuid;
+  bool hasCache = _dyld_get_shared_cache_uuid(uuid);
+  if (!hasCache)
+    return nullptr;
+
+  size_t cacheLength;
+  __block uptr cacheStart = (uptr)_dyld_get_shared_cache_range(&cacheLength);
+  CHECK(cacheStart && cacheLength);
+
+  __block mach_header *dyldHdr = nullptr;
+  int res = dyld_shared_cache_iterate_text(
+      uuid, ^(const dyld_shared_cache_dylib_text_info *info) {
+        CHECK_GE(info->version, 2);
+        mach_header *hdr =
+            (mach_header *)(cacheStart + info->textSegmentOffset);
+        if (IsDyldHdr(hdr))
+          dyldHdr = hdr;
+      });
+  CHECK_EQ(res, 0);
+
+  return dyldHdr;
+}
+
 const mach_header *get_dyld_hdr() {
-  if (!dyld_hdr) dyld_hdr = get_dyld_image_header();
+  if (!dyld_hdr) {
+    // On macOS 13+, dyld itself has moved into the shared cache.  Looking it up
+    // via vm_region_recurse_64() causes spins/hangs/crashes.
+    if (GetMacosAlignedVersion() >= MacosVersion(13, 0)) {
+      dyld_hdr = GetDyldImageHeaderViaSharedCache();
+      if (!dyld_hdr) {
+        Printf(
+            "Failed to lookup the dyld image header in the shared cache on "
+            "macOS 13+ (or no shared cache in use).  Falling back to lookup via"
+            "vm_region_recurse_64().\n");
+        dyld_hdr = GetDyldImageHeaderViaVMRegion();
+      }
+    } else {
+      dyld_hdr = GetDyldImageHeaderViaVMRegion();
+    }
+    CHECK(dyld_hdr);
+  }
 
   return dyld_hdr;
 }


        


More information about the llvm-commits mailing list