From a72b98ed5a357bb380d81f07f3f36946aa729bb2 Mon Sep 17 00:00:00 2001 From: Mark Rowe Date: Mon, 23 Feb 2026 23:26:27 -0800 Subject: [DSC] Simplify file mapping to fix intermittent unrelocated pointers The `FileAccessorCache`'s LRU eviction could discard a file's mapped data after slide info had already been applied to it. Future accesses to the file produced a fresh mapping, but failed to reapply the slide info. This could result in pointers not correctly being slid, such as in https://github.com/Vector35/binaryninja-api/issues/7689. The LRU cache existed to stay within OS file descriptor limits, since the old `MappedFile` held its fd open for the lifetime of the mapping. There's no real reason for it to hold the file descriptor open like this. Closing it after `mmap` is sufficient to avoid the file descriptor limits. `MappedFileRegion` replaces the combination of `FileAccessorCache`, `WeakFileAccessor`, and `MappedFileAccessor`. It closes the fd immediately after mmap, so all files can stay mapped without consuming descriptors, making the cache unnecessary. `MappedFileRegion` is owned directly by the `CacheEntry` for its full lifetime. Slide info is applied exactly once to each `MappedFileRegion`. --- view/sharedcache/core/MappedFile.cpp | 193 ----------------------------------- 1 file changed, 193 deletions(-) delete mode 100644 view/sharedcache/core/MappedFile.cpp (limited to 'view/sharedcache/core/MappedFile.cpp') diff --git a/view/sharedcache/core/MappedFile.cpp b/view/sharedcache/core/MappedFile.cpp deleted file mode 100644 index 21bda4f8..00000000 --- a/view/sharedcache/core/MappedFile.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#ifdef _MSC_VER - #include -#else - #include - #include - #include - #include -#endif - -#include "MappedFile.h" -#include "binaryninjaapi.h" - -#ifndef _MSC_VER -uint64_t AdjustFileDescriptorLimit() -{ - // The soft file descriptor limit on Linux and Mac is a lot lower than - // on Windows (1024 for Linux, 256 for Mac). Recent iOS shared caches - // have 60+ files which may not leave much headroom if a user opens - // more than one at a time. Attempt to increase the file descriptor - // limit to 1024, and limit ourselves to caching half of them as a - // memory vs performance trade-off (closing and re-opening a file - // requires parsing and applying the slide information again). - uint64_t maxFPLimit = 1024; - - // check for BN_SHAREDCACHE_FP_MAX - // if it exists, set maxFPLimit to that value - if (auto env = getenv("BN_SHAREDCACHE_FP_MAX"); env) - { - // FIXME behav on 0 here is unintuitive, '0123' will interpret as octal and be 83 according to manpage. meh. - maxFPLimit = strtoull(env, nullptr, 0); - if (maxFPLimit < 10) - { - BinaryNinja::LogWarn( - "BN_SHAREDCACHE_FP_MAX set to below 10. A value of at least 10 is recommended for performant analysis " - "on SharedCache Binaries."); - } - if (maxFPLimit == 0) - { - BinaryNinja::LogError("BN_SHAREDCACHE_FP_MAX set to 0. Adjusting to 1"); - maxFPLimit = 1; - } - } - - rlimit rlim {}; - getrlimit(RLIMIT_NOFILE, &rlim); - uint64_t previousLimit = rlim.rlim_cur; - uint64_t targetLimit = std::min(maxFPLimit, rlim.rlim_max); - if (rlim.rlim_cur < targetLimit) - { - rlim.rlim_cur = targetLimit; - if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) - { - perror("setrlimit(RLIMIT_NOFILE)"); - rlim.rlim_cur = previousLimit; - } - } - - maxFPLimit = rlim.rlim_cur / 2; - return maxFPLimit; -} - -MappedFile::~MappedFile() -{ - Unmap(); - if (fd) - fclose(fd); -} - -std::optional MappedFile::OpenFile(const std::string& path) -{ - MappedFile file; - file._mmap = nullptr; - file.fd = fopen(path.c_str(), "r"); - if (file.fd == nullptr) - return std::nullopt; - - fseek(file.fd, 0L, SEEK_END); - file.len = ftell(file.fd); - fseek(file.fd, 0L, SEEK_SET); - - return file; -} - -MapStatus MappedFile::Map() -{ - if (_mmap) - return MapStatus::Success; - - void* result = mmap(nullptr, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fileno(fd), 0u); - if (result == MAP_FAILED) - { - BinaryNinja::LogErrorF("mmap failed: {}", strerror(errno)); // Use errno to log the reason - return MapStatus::Error; - } - _mmap = static_cast(result); - - return MapStatus::Success; -} - -MapStatus MappedFile::Unmap() -{ - if (_mmap) - { - munmap(_mmap, len); - _mmap = nullptr; - } - return MapStatus::Success; -} -#else -uint64_t AdjustFileDescriptorLimit() -{ - return 0x1000000; -} - -MappedFile::~MappedFile() -{ - Unmap(); - if (hFile) - CloseHandle(hFile); -} - -std::optional MappedFile::OpenFile(const std::string& path) -{ - MappedFile file; - file._mmap = nullptr; - file.hFile = CreateFile(path.c_str(), // file name - GENERIC_READ, // desired access (read-only) - FILE_SHARE_READ, // share mode - NULL, // security attributes - OPEN_EXISTING, // creation disposition - FILE_ATTRIBUTE_NORMAL, // flags and attributes - NULL); // template file - - if (file.hFile == INVALID_HANDLE_VALUE) - return std::nullopt; - - LARGE_INTEGER fileSize; - if (!GetFileSizeEx(file.hFile, &fileSize)) - { - CloseHandle(file.hFile); - return std::nullopt; - } - file.len = static_cast(fileSize.QuadPart); - - return file; -} - -MapStatus MappedFile::Map() -{ - if (_mmap) - return MapStatus::Success; - - HANDLE hMapping = CreateFileMapping(hFile, // file handle - NULL, // security attributes - PAGE_WRITECOPY, // protection - 0, // maximum size (high-order DWORD) - 0, // maximum size (low-order DWORD) - NULL); // name of the mapping object - - if (hMapping == NULL) - { - CloseHandle(hFile); - return MapStatus::Error; - } - - _mmap = static_cast(MapViewOfFile(hMapping, // handle to the file mapping object - FILE_MAP_COPY, // desired access - 0, // file offset (high-order DWORD) - 0, // file offset (low-order DWORD) - 0)); // number of bytes to map (0 = entire file) - - if (_mmap == nullptr) - { - CloseHandle(hMapping); - CloseHandle(hFile); - return MapStatus::Error; - } - - CloseHandle(hMapping); - CloseHandle(hFile); - - return MapStatus::Success; -} - -MapStatus MappedFile::Unmap() -{ - if (_mmap) - { - UnmapViewOfFile(_mmap); - } - return MapStatus::Success; -} -#endif -- cgit v1.3.1