summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/MappedFileRegion.h
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/MappedFileRegion.h
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/MappedFileRegion.h')
-rw-r--r--view/sharedcache/core/MappedFileRegion.h72
1 files changed, 72 insertions, 0 deletions
diff --git a/view/sharedcache/core/MappedFileRegion.h b/view/sharedcache/core/MappedFileRegion.h
new file mode 100644
index 00000000..7cbf2100
--- /dev/null
+++ b/view/sharedcache/core/MappedFileRegion.h
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "binaryninjaapi.h"
+
+#include <memory>
+#include <mutex>
+#include <span>
+#include <stdint.h>
+#include <string>
+
+class UnmappedAccessException : public std::runtime_error
+{
+public:
+ UnmappedAccessException(uint64_t offset, uint64_t fileLength)
+ : std::runtime_error(fmt::format("Tried to access offset {:#x} in file of length {:#x}", offset, fileLength))
+ {}
+};
+
+// A memory-mapped region of a file. Owns the mmap for its entire lifetime.
+// Data is mapped using MAP_PRIVATE, so modifications to the data are not persisted to disk.
+class MappedFileRegion
+{
+ uint8_t* m_data = nullptr;
+ size_t m_length = 0;
+ std::string m_path;
+ std::once_flag m_slidOnce;
+
+ MappedFileRegion(const MappedFileRegion&) = delete;
+ MappedFileRegion& operator=(const MappedFileRegion&) = delete;
+ MappedFileRegion(MappedFileRegion&&) = delete;
+ MappedFileRegion& operator=(MappedFileRegion&&) = delete;
+
+ struct PrivateTag {};
+
+public:
+ MappedFileRegion(PrivateTag, uint8_t* data, size_t length, std::string path);
+ ~MappedFileRegion();
+
+ // Opens file, mmaps with MAP_PRIVATE, closes fd immediately.
+ // Returns nullptr on failure.
+ static std::shared_ptr<MappedFileRegion> Open(const std::string& path);
+
+ const std::string& Path() const { return m_path; }
+ size_t Length() const { return m_length; }
+
+ // Run `fn` exactly once. All callers block until the work is complete.
+ template <typename F>
+ void SlideOnce(F&& fn) { std::call_once(m_slidOnce, std::forward<F>(fn)); }
+
+ // Typed reads -- bounds-checked with overflow-safe checks:
+ // if (sizeof(T) > m_length || offset > m_length - sizeof(T))
+ uint8_t ReadUInt8(size_t offset) const;
+ int8_t ReadInt8(size_t offset) const;
+ uint16_t ReadUInt16(size_t offset) const;
+ int16_t ReadInt16(size_t offset) const;
+ uint32_t ReadUInt32(size_t offset) const;
+ int32_t ReadInt32(size_t offset) const;
+ uint64_t ReadUInt64(size_t offset) const;
+ int64_t ReadInt64(size_t offset) const;
+
+ std::string ReadNullTermString(size_t offset, size_t maxLen = -1) const;
+ void Read(void* dest, size_t offset, size_t length) const;
+ BinaryNinja::DataBuffer ReadBuffer(size_t offset, size_t length) const;
+ std::span<const uint8_t> ReadSpan(size_t offset, size_t length) const;
+
+ // Write. This is not persisted to disk. Used for applying slides only.
+ void WriteUInt64(size_t offset, uint64_t value);
+
+private:
+ template <typename T>
+ T Read(size_t offset) const;
+};