Loading...
common/ProcessAtlas.cpp dyld-1235.2 dyld-1042.1
--- dyld/dyld-1235.2/common/ProcessAtlas.cpp
+++ dyld/dyld-1042.1/common/ProcessAtlas.cpp
@@ -24,8 +24,6 @@
 
 #include <TargetConditionals.h>
 
-#if !TARGET_OS_EXCLAVEKIT
-
 #include <atomic>
 #include <cstring>
 #include <Block.h>
@@ -41,8 +39,8 @@
 #include <sys/stat.h>
 #include <sys/fsgetpath.h>
 
+#include <mach/mach_vm.h>
 #include <mach/mach_time.h> // mach_absolute_time()
-#include <mach/mach_vm.h>
 #include <mach-o/dyld_priv.h> // FIXME: We can remove this once we fully integrate into dyld4
 #include "dyld_cache_format.h"
 //FIXME: We should remove this header
@@ -78,8 +76,6 @@
 #else
 #define _transactionalAllocator Allocator::defaultAllocator()
 #endif
-
-#define BLEND_KERN_RETURN_LOCATION(kr, loc) (kr) = ((kr & 0x00ffffff) | loc<<24);
 
 namespace {
 static const size_t kCachePeekSize = 0x4000;
@@ -128,28 +124,13 @@
     : _size(size), _bitmap(UniquePtr<std::byte>((std::byte*)allocator.malloc((size+7)/8))) {}
 
 Bitmap::Bitmap(Allocator& allocator, std::span<std::byte>& data) {
-    uint64_t encodedSize = 0;
-    if (!readPVLEUInt64(data, encodedSize)) {
-        _size = 0;
-        _bitmap = nullptr;
-        return;
-    }
-    _size = (size_t)encodedSize;
+    _size = (size_t)readPVLEUInt64(data);
     const size_t byteSize = (_size+7)/8;
     _bitmap = UniquePtr<std::byte>((std::byte*)allocator.malloc(byteSize));
     _bitmap.withUnsafe([&](std::byte* bitmap) {
         std::copy(&data[0], &data[byteSize], &bitmap[0]);
     });
     data = data.last(data.size()-byteSize);
-}
-
-Bitmap::Bitmap(Bitmap&& other) {
-    swap(other);
-}
-
-Bitmap& Bitmap::operator=(Bitmap&& other) {
-    swap(other);
-    return *this;
 }
 
 void Bitmap::setBit(size_t bit) {
@@ -429,7 +410,7 @@
     }
 
     // mmap whole file temporarily
-    void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE | MAP_RESILIENT_CODESIGN, fd, 0);
+    void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
     if ( tempMapping == MAP_FAILED ) {
         ::close(fd);
         return nullptr;
@@ -598,14 +579,11 @@
 #if BUILDING_DYLD
 Image::Image(RuntimeState* state, Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, const Loader* ldr)
     :   _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((void*)ldr->loadAddress(*state)) {
-        auto fileID = ldr->fileID(*state);
+        auto fileID = ldr->fileID(state->fileManager);
         if (fileID.inode() &&  fileID.device()) {
-            _file = state->fileManager.fileRecordForFileID(ldr->fileID(*state));
-            if ( _file.volume().empty() ) {
-                _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
-            }
+            _file = state->fileManager.fileRecordForFileID(ldr->fileID(state->fileManager));
         } else {
-            _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
+            _file = state->fileManager.fileRecordForPath(ldr->path());
         }
     }
 #endif
@@ -634,38 +612,26 @@
     using std::swap;
 
     if (this == &other) { return; }
-    swap(_uuid,                 other._uuid);
-    swap(_ml,                   other._ml);
-    swap(_sharedCacheSlide,     other._sharedCacheSlide);
-    swap(_rebasedAddress,       other._rebasedAddress);
-    swap(_mapper,               other._mapper);
-    swap(_sharedCache,          other._sharedCache);
-    swap(_installname,          other._installname);
-    swap(_file,                 other._file);
-    swap(_uuidLoaded,           other._uuidLoaded);
-    swap(_installnameLoaded,    other._installnameLoaded);
-    swap(_mapperFailed,         other._mapperFailed);
+    std::swap(_uuid,                other._uuid);
+    std::swap(_ml,                  other._ml);
+    std::swap(_sharedCacheSlide,    other._sharedCacheSlide);
+    std::swap(_rebasedAddress,      other._rebasedAddress);
+    std::swap(_mapper,              other._mapper);
+    std::swap(_sharedCache,         other._sharedCache);
+    std::swap(_installname,         other._installname);
+    std::swap(_file,                other._file);
+    std::swap(_uuidLoaded,          other._uuidLoaded);
+    std::swap(_installnameLoaded,   other._installnameLoaded);
 }
 
 const MachOLoaded* Image::ml() const {
-    if (_mapperFailed) {
-        return nullptr;
-    }
+    void* slidML = (void*)rebasedAddress();
     if (!_ml) {
-        void* slidML = (void*)rebasedAddress();
         // Note, using 4k here as we might be an arm64e process inspecting an x86_64 image, which uses 4k pages
-        if (!_mapper && !_mapperFailed) {
+        if (!_mapper) {
             _mapper = Mapper::mapperForMachO(_transactionalAllocator, _file, _uuid, _rebasedAddress);
         }
-        if (!_mapper) {
-            _mapperFailed = true;
-            return nullptr;
-        }
         _ml = _mapper->map<MachOLoaded>(slidML, 4096);
-        if (!_ml) {
-           _mapperFailed = true;
-           return nullptr;
-        }
         size_t size = _ml->sizeofcmds;
         if ( _ml->magic == MH_MAGIC_64 ) {
             size += sizeof(mach_header_64);
@@ -674,10 +640,6 @@
         }
         if (size > 4096) {
             _ml = _mapper->map<MachOLoaded>(slidML, size);
-            if (!_ml) {
-               _mapperFailed = true;
-               return nullptr;
-            }
         }
     }
     // This is a bit of a mess. With compact info this will be unified, but for now we use a lot of hacky abstactions here to deal with
@@ -689,7 +651,7 @@
     if (!_uuidLoaded) {
         uuid_t fileUUID;
         const MachOLoaded* mh = ml();
-        if (mh && mh->hasMachOMagic()) {
+        if (mh->hasMachOMagic()) {
             if (mh->getUuid(fileUUID))
                 _uuid = UUID(fileUUID);
         }
@@ -705,9 +667,7 @@
 
 const char* Image::installname() const {
     if (!_installnameLoaded) {
-        if (ml()) {
-            _installname = ml()->installName();
-        }
+        _installname = ml()->installName();
         _installnameLoaded = true;
     }
     return _installname;
@@ -730,12 +690,10 @@
 }
 
 uint32_t Image::pointerSize() {
-    if (!ml()) { return 0; }
     return ml()->pointerSize();
 }
 
 bool Image::forEachSegment(void (^block)(const char* segmentName, uint64_t vmAddr, uint64_t vmSize, int perm)) {
-    if (!ml()) { return false; }
     __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
     ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
         uint64_t vmAddr = 0x0;
@@ -754,7 +712,6 @@
 }
 
 bool Image::forEachSection(void (^block)(const char* segmentName, const char* sectionName, uint64_t vmAddr, uint64_t vmSize)) {
-    if (!ml()) { return false; }
     __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
     ml()->forEachSection(^(const MachOLoaded::SectionInfo &info, bool malformedSectionRange, bool &stop) {
         uint64_t sectAddr = 0x0;
@@ -769,7 +726,6 @@
 }
 
 bool Image::contentForSegment(const char* segmentName, void (^contentReader)(const void* content, uint64_t vmAddr, uint64_t vmSize)) {
-    if (!ml()) { return false; }
     __block bool result = false;
     __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
     ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
@@ -975,7 +931,7 @@
                     continue;
 
                 // FIXME: The memory managemnt here is awful, fix with allocators
-                auto cacheFile = fileManager.fileRecordForPath(_ephemeralAllocator, cachePath);
+                auto cacheFile = fileManager.fileRecordForPath(cachePath);
                 auto cache = Atlas::SharedCache::createForFileRecord(_ephemeralAllocator, std::move(cacheFile));
                 if (cache) {
                     cache.withUnsafe([&](auto cachePtr){
@@ -1096,7 +1052,7 @@
             return nullptr;
     }
     // TODO: Create Path extension helpers for FileRecord
-    auto localSymbolsCacheFile = _file.fileManager().fileRecordForPath(_ephemeralAllocator, localSymbolsCachePath);
+    auto localSymbolsCacheFile = _file.fileManager().fileRecordForPath(localSymbolsCachePath);
     auto [fileMapper, baseAddress] = Mapper::mapperForSharedCacheLocals(_ephemeralAllocator, localSymbolsCacheFile);
     if (!fileMapper) { return nullptr; }
     // Use placement new since operator new is not available
@@ -1245,8 +1201,6 @@
     pid_t   pid;
     *kr = pid_for_task(_task, &pid);
     if ( *kr != KERN_SUCCESS ) {
-        BLEND_KERN_RETURN_LOCATION(*kr, 0xea);
-        *kr |= 0xeb000000UL;
         return nullptr;
     }
 
@@ -1254,7 +1208,6 @@
     mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
     *kr = task_info(_task, MACH_TASK_BASIC_INFO, (task_info_t)&ti, &count);
     if ( *kr != KERN_SUCCESS ) {
-        BLEND_KERN_RETURN_LOCATION(*kr, 0xe9);
         return nullptr;
     }
 
@@ -1278,7 +1231,6 @@
             mach_vm_size_t readSize = 0;
             *kr = mach_vm_read_overwrite(_task, address, size, (mach_vm_address_t)&unsafeBytes[0], &readSize);
             if ( *kr != KERN_SUCCESS ) {
-                BLEND_KERN_RETURN_LOCATION(*kr, 0xe8);
                 return;
             }
             auto mf = MachOFile::isMachO((const void*)unsafeBytes);
@@ -1291,7 +1243,7 @@
                     executablePath[len] = '\0';
                 }
                 SharedPtr<Mapper> mapper = nullptr;
-                auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
+                auto file = _fileManager.fileRecordForPath(executablePath);
                 uuid_t rawUUID;
                 mf->getUuid(rawUUID);
                 auto uuid = UUID(rawUUID);
@@ -1303,7 +1255,7 @@
                     executablePath[len] = '\0';
                 }
                 SharedPtr<Mapper> mapper = nullptr;
-                auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
+                auto file = _fileManager.fileRecordForPath(executablePath);
                 uuid_t rawUUID;
                 mf->getUuid(rawUUID);
                 auto uuid = UUID(rawUUID);
@@ -1339,12 +1291,10 @@
     task_dyld_info_data_t task_dyld_info;
     *kr = task_info(_task, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);
     if ( *kr != KERN_SUCCESS ) {
-        BLEND_KERN_RETURN_LOCATION(*kr, 0xef);
         return nullptr;
     }
     //The kernel will return MACH_VM_MIN_ADDRESS for an executable that has not had dyld loaded
     if (task_dyld_info.all_image_info_addr == MACH_VM_MIN_ADDRESS) {
-        BLEND_KERN_RETURN_LOCATION(*kr, 0xee);
         return nullptr;
     }
     uint8_t remoteBuffer[16*1024];
@@ -1355,7 +1305,6 @@
         *kr = mach_vm_read_overwrite(_task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size,
                                      (mach_vm_address_t)&remoteBuffer[0], &readSize);
         if (*kr != KERN_SUCCESS) {
-            BLEND_KERN_RETURN_LOCATION(*kr, 0xed);
             // If we cannot read the all image info this is game over
             return nullptr;
         }
@@ -1376,7 +1325,6 @@
         auto compactInfo = UniquePtr<std::byte>((std::byte*)_transactionalAllocator.malloc((size_t)compactInfoSize));
         *kr = mach_vm_read_overwrite(_task, compactInfoAddress, compactInfoSize, (mach_vm_address_t)&*compactInfo, &readSize);
         if (*kr != KERN_SUCCESS) {
-            BLEND_KERN_RETURN_LOCATION(*kr, 0xec);
             // The read failed, chances are the process mutated the compact info, retry
             continue;
         }
@@ -1385,7 +1333,6 @@
         if (!result->valid()) {
             // Something blew up we don't know what
             *kr = KERN_FAILURE;
-            BLEND_KERN_RETURN_LOCATION(*kr, 0xeb);
             return nullptr;
         }
         return result;
@@ -1630,7 +1577,7 @@
         if (!serializer.deserialize(data)) {
             // Deerialization failed, reset the snapshot and mark invalid
             _images.clear();
-            _bitmap             = nullptr;
+            _bitmap             = Bitmap();
             _sharedCache        = nullptr;
             _platform           = 0;
             _initialImageCount  = 0;
@@ -1653,7 +1600,7 @@
         if (processedCacheImages) { return; }
         processedCacheImages = true;
         for (auto i = 0; i < _sharedCache->imageCount(); ++i) {
-            if (!_bitmap->checkBit(i)) { continue; }
+            if (!_bitmap.checkBit(i)) { continue; }
             _sharedCache->withImageForIndex(i, ^(Image *image) {
                 block(image);
             });
@@ -1676,8 +1623,8 @@
         if (processedCacheImages) { return; }
         if (!_sharedCache) { return; }
         for (auto i = 0; i < _sharedCache->imageCount(); ++i) {
-            if (!_bitmap->checkBit(i)) { continue; }
-            if (other._sharedCache && other._bitmap->checkBit(i)) { continue; }
+            if (!_bitmap.checkBit(i)) { continue; }
+            if (other._sharedCache && other._bitmap.checkBit(i)) { continue; }
             _sharedCache->withImageForIndex(i, ^(Image *image) {
                 block(image);
             });
@@ -1719,7 +1666,7 @@
 void ProcessSnapshot::addImages(RuntimeState* state, const std::span<const Loader*>& loaders) {
     for (auto& ldr : loaders) {
         if (_sharedCache && ldr->dylibInDyldCache) {
-            _bitmap->setBit(ldr->ref.index);
+            _bitmap.setBit(ldr->ref.index);
         } else {
             _images.insert(_transactionalAllocator.makeUnique<Image>(state, _ephemeralAllocator, identityMapper(), ldr));
         }
@@ -1741,11 +1688,11 @@
 #if BUILDING_DYLD || BUILDING_UNIT_TESTS
 void ProcessSnapshot::addSharedCache(SharedCache&& sharedCache) {
     _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(std::move(sharedCache));
-    _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, _sharedCache->imageCount());
-}
-
-/// Assumes the mach_header parameter is in the range of the shared cache. Otherwise asserts
+    _bitmap = Bitmap(_transactionalAllocator, _sharedCache->imageCount());
+}
+
 void ProcessSnapshot::addSharedCacheImage(const struct mach_header* mh) {
+    assert(mh->flags & MH_DYLIB_IN_CACHE);
     auto header = (dyld_cache_header*)_sharedCache->rebasedAddress();
     auto headerBytes = (uint8_t*)header;
     auto slide = (uint64_t)header - header->sharedRegionStart;
@@ -1754,7 +1701,7 @@
         return (other.loadAddress == ((uint64_t)mh-slide));
     });
     assert(i != images.end());
-    _bitmap->setBit(i-images.begin());
+    _bitmap.setBit(i-images.begin());
 }
 
 
@@ -1913,37 +1860,22 @@
     }
 }
 
-bool ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
-    uint64_t flags = 0;
-    if (!readPVLEUInt64(data, flags)
-        || !readPVLEUInt64(data, rebasedAddress)) {
-        return false;
-    }
+void ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
+    uint64_t flags = readPVLEUInt64(data);
+    rebasedAddress = readPVLEUInt64(data);
     if (flags & kMappedFileFlagsHasUUID) {
-        if (data.size() < 16) {
-            return false;
-        }
         uuid = UUID(&data[0]);
         data = data.last(data.size()-16);
     }
     if (flags & kMappedFileFlagsHasFileID) {
-        uint64_t volumeIndex = 0;
-        uint64_t objectID = 0;
-        if (!readPVLEUInt64(data, volumeIndex)
-            || !readPVLEUInt64(data, objectID)
-            || volumeIndex >= _volumeUUIDs.size()) {
-            return false;
-        }
+        uint64_t volumeIndex = readPVLEUInt64(data);
+        uint64_t objectID = readPVLEUInt64(data);
         file = _fileManager.fileRecordForVolumeUUIDAndObjID(_volumeUUIDs[(size_t)volumeIndex], objectID);
     }
     if (flags & kMappedFileFlagsHasFilePath) {
-        uint64_t pathOffset = 0;
-        if (!readPVLEUInt64(data, pathOffset) || pathOffset >= _stringTableBuffer.size()) {
-            return false;
-        }
-        file = _fileManager.fileRecordForPath(_ephemeralAllocator, &_stringTableBuffer[(size_t)pathOffset]);
-    }
-    return true;
+        uint64_t pathOffset = readPVLEUInt64(data);
+        file = _fileManager.fileRecordForPath(&_stringTableBuffer[(size_t)pathOffset]);
+    }
 }
 
 Vector<std::byte> ProcessSnapshot::Serializer::serialize() {
@@ -1951,7 +1883,6 @@
     _genCount++;
     auto result = Vector<std::byte>(_ephemeralAllocator);
     // We need unique all the strings and UUIDs and place them in sorted tables
-    // FIXME: We should use vectors and sort them since it faster in pathological cases, but we need a non-allocating sort
     OrderedSet<const char*, lsl::ConstCharStarCompare>   stringSet(_ephemeralAllocator);
     OrderedSet<UUID>                                     volumeUUIDSet(_ephemeralAllocator);
     if (PAGE_SIZE == 16384) {
@@ -1974,7 +1905,7 @@
         if (file.persistent()) {
             volumeUUIDSet.insert(file.volume());
         } else if (auto filePath = file.getPath()) {
-            stringSet.insert(filePath);
+            stringSet.insert(file.getPath());
         } else {
             stringSet.insert("???");
         }
@@ -2017,7 +1948,7 @@
     if (_processFlags & kProcessFlagsHasSharedCache) {
         uint64_t address = _sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
         emitMappedFileInfo(address, _sharedCache->uuid(), _sharedCache->file(), result);
-        _bitmap->emit(result);
+        _bitmap.emit(result);
     }
 
     emitPVLEUInt64(_images.size(), result);
@@ -2038,10 +1969,6 @@
 
 bool ProcessSnapshot::Serializer::deserialize(const std::span<std::byte> data) {
     auto i = data;
-    if (i.size() < 36) {
-        // Ensure data is at least large enough to read the header
-        return false;
-    }
     // Confirm magic
     _magic              = read<uint32_t>(i);
     _version            = read<uint32_t>(i);
@@ -2051,39 +1978,29 @@
     _timestamp          = read<uint64_t>(i);
     _crc32c             = read<uint32_t>(i);
     if (_magic != kMagic) {
-        return false;
+        assert(0);
     }
     if (_version != 0) {
-        return false;
+        assert(0);
     }
     CRC32c checksumer;
     checksumer(std::span(&data[0], 32));
     checksumer((uint32_t)0); // Zero out the actual checksum
     checksumer(std::span(&data[36], data.size() - 36));
     if (_crc32c != checksumer) {
-        return false;
-    }
-    uint64_t volumeUUIDCount = 0;
-    if (!readPVLEUInt64(i, _processFlags)
-        || !readPVLEUInt64(i, _platform)
-        || !readPVLEUInt64(i, _initialImageCount)
-        || !readPVLEUInt64(i, _dyldState)
-        || !readPVLEUInt64(i, volumeUUIDCount)) {
-        return false;
-    }
-    if (i.size() < volumeUUIDCount*16) {
-        return false;
-    }
+        assert(0);
+    }
+    _processFlags           = readPVLEUInt64(i);
+    _platform               = readPVLEUInt64(i);
+    _initialImageCount      = readPVLEUInt64(i);
+    _dyldState              = readPVLEUInt64(i);
+    auto volumeUUIDCount    = readPVLEUInt64(i);
     for (auto j = 0; j < volumeUUIDCount; ++j) {
         UUID volumeUUID(&i[j*16]);
         _volumeUUIDs.push_back(volumeUUID);
     }
     i = i.last((size_t)(i.size()-(16*volumeUUIDCount)));
-    uint64_t stringTableSize = 0;
-    if (!readPVLEUInt64(i, stringTableSize)
-        || i.size() < stringTableSize) {
-        return false;
-    }
+    auto stringTableSize    = readPVLEUInt64(i);
     _stringTableBuffer.reserve((size_t)stringTableSize);
     std::copy((uint8_t*)&i[0], (uint8_t*)&i[(size_t)stringTableSize], std::back_inserter(_stringTableBuffer));
     i = i.last((size_t)(i.size()-stringTableSize));
@@ -2092,8 +2009,7 @@
         uint64_t rebasedAddress;
         UUID uuid;
         FileRecord file;
-        if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
-            return false;
+        readMappedFileInfo(i, rebasedAddress, uuid, file);
         rebasedAddress = rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
         SharedPtr<Mapper> mapper = nullptr;
         if (_processSnapshot._useIdentityMapper) {
@@ -2111,33 +2027,30 @@
 
         _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), mapper,
                                                                        rebasedAddress, _processFlags & kProcessFlagsHasPrivateCache);
-        _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, i);
-        if (_bitmap->size() == 0) {
-            return false;
-        }
-    }
-    uint64_t imageCount = 0;
-    if (!readPVLEUInt64(i, imageCount)) {
-        return false;
-    }
+        _bitmap = Bitmap(_transactionalAllocator, i);
+    }
+    auto imageCount = readPVLEUInt64(i);
     uint64_t lastAddress = 0;
     for (auto j = 0; j < imageCount; ++j) {
         uint64_t rebasedAddress;
         UUID uuid;
         FileRecord file;
-        if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
-            return false;
+        readMappedFileInfo(i, rebasedAddress, uuid, file);
         rebasedAddress = (rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096)) + lastAddress;
         lastAddress = rebasedAddress;
         SharedPtr<Mapper> mapper = nullptr;
         if (_processSnapshot._useIdentityMapper) {
             mapper = _processSnapshot.identityMapper();
-        }
+        } else {
 #if BUILDING_DYLD || BUILDING_UNIT_TESTS
-        else {
             mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
-        }
+#else
+            mapper = Mapper::mapperForMachO(_transactionalAllocator, file, uuid, (const void*)rebasedAddress);
 #endif
+        }
+        if (!mapper) {
+            return false;
+        }
         auto image = Image(_ephemeralAllocator, std::move(file), mapper, (const struct mach_header*)rebasedAddress, uuid);
         _images.insert(_transactionalAllocator.makeUnique<Image>(std::move(image)));
     }
@@ -2146,4 +2059,3 @@
 
 };
 };
-#endif // !TARGET_OS_EXCLAVEKIT