summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/FileAccessorCache.cpp
diff options
context:
space:
mode:
authorMark Rowe <mark@vector35.com>2026-02-23 23:26:27 -0800
committerMark Rowe <mark@vector35.com>2026-02-24 14:24:54 -0800
commita72b98ed5a357bb380d81f07f3f36946aa729bb2 (patch)
treeca48b3607721fa2c109b7989ae4b911bab89ea6d /view/sharedcache/core/FileAccessorCache.cpp
parent3eda43f185a0411538745a99e251122e6a9192e0 (diff)
[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`.
Diffstat (limited to 'view/sharedcache/core/FileAccessorCache.cpp')
-rw-r--r--view/sharedcache/core/FileAccessorCache.cpp95
1 files changed, 0 insertions, 95 deletions
diff --git a/view/sharedcache/core/FileAccessorCache.cpp b/view/sharedcache/core/FileAccessorCache.cpp
deleted file mode 100644
index 28aab15d..00000000
--- a/view/sharedcache/core/FileAccessorCache.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#include "FileAccessorCache.h"
-
-#include <cassert>
-
-CacheAccessorID GetCacheAccessorID(const std::string& filePath)
-{
- constexpr std::hash<std::string> hasher;
- return static_cast<CacheAccessorID>(hasher(filePath));
-}
-
-FileAccessorCache::FileAccessorCache(size_t cacheSize)
-{
- m_cacheSize = cacheSize;
- m_accessors = {};
-}
-
-void FileAccessorCache::EvictLastUsed()
-{
- if (m_cache.empty())
- return;
- // Evict the least recently used element.
- const auto lruID = m_cache.front();
- m_cache.pop_front();
- // Ensure the least recently used ID actually exists in the accessors map.
- assert(m_accessors.find(lruID) != m_accessors.end() && "Evicting non-existent ID from accessors map");
- m_accessors.erase(lruID);
-}
-
-FileAccessorCache& FileAccessorCache::Global()
-{
- static FileAccessorCache cache {};
- return cache;
-}
-
-WeakFileAccessor FileAccessorCache::Open(const std::string& filePath)
-{
- const auto id = GetCacheAccessorID(filePath);
- std::unique_lock lock(m_mutex);
-
- // Check if the file is already in the cache.
- if (const auto it = m_accessors.find(id); it != m_accessors.end())
- {
- // Move the accessed ID to the back so we keep it in the cache.
- auto pos = std::find(m_cache.begin(), m_cache.end(), id);
- if (pos != m_cache.end())
- m_cache.erase(pos);
- m_cache.push_back(id);
-
- return WeakFileAccessor(it->second, filePath);
- }
-
- // Evict if we are going to go above the limit.
- while (m_cache.size() >= m_cacheSize)
- EvictLastUsed();
-
- // Create a new file accessor and add it to the cache.
- auto accessor = MappedFileAccessor::Open(filePath);
- if (accessor == nullptr)
- {
- // We failed to open the file, we must throw hard!
- // TODO: Make this mechanism more thought out...
- throw std::runtime_error("Failed to open file: " + filePath);
- }
- auto sharedAccessor = std::make_shared<MappedFileAccessor>(std::move(*accessor));
- m_accessors.insert_or_assign(id, sharedAccessor);
- m_cache.push_back(id);
-
- return WeakFileAccessor(sharedAccessor, filePath);
-}
-
-void FileAccessorCache::RemoveAccessor(const CacheAccessorID id)
-{
- std::unique_lock lock(m_mutex);
- m_accessors.erase(id);
-}
-
-std::shared_ptr<MappedFileAccessor> WeakFileAccessor::lock()
-{
- auto sharedPtr = m_weakPtr.lock();
- if (!sharedPtr)
- {
- // This will revive other weak pointers to the same shared ptr.
- // Update the weak pointer to the newly created shared instance
- m_weakPtr = FileAccessorCache::Global().Open(m_filePath).m_weakPtr;
- sharedPtr = m_weakPtr.lock();
-
- // Call the function registered with `RegisterReviveCallback`.
- // TODO: This races if two functions cannot acquire and revive the same file at the same time.
- // TODO: This will be called twice.
- if (m_reviveCallback.has_value())
- (*m_reviveCallback)(*sharedPtr);
- }
-
- return sharedPtr;
-}