Open Sewer56 opened 1 year ago
Hi,
I have been trying to implement something similar in PR #14. I think it makes more sense to implement this as some sort of Mmap::from_raw()
and Mmap::into_raw()
API that bypasses using MmapOptions
entirely, since there is no reason to specify the options (you already should have a pointer and a size).
The reason I haven't made much progress on this recently, is that Microsoft Windows requires you to call VirtualFree
on the entire allocation that you originally received from VirtualAlloc
. Since mmap-rs allows you to split and merge Mmap
objects, that original allocation needs to be tracked with a reference counted object (see PR #29), otherwise VirtualFree
could fail. However, this also means that for Mmap::from_raw()
there is currently no way to retrieve that reference counted object (assuming there is one).
I think the constraints are:
Mmap::from_raw()
should only be used on the original allocation pointer and size.Mmap::into_raw()
should probably fail for split Mmap
objects on Microsoft Windows, i.e. return a Result
.Mmap::into_raw()
needs to ensure that VirtualFree
/munmap
doesn't get called on the allocation.Aah, I see. I also now understand why SharedArea
is around for the Windows implementation.
I think the constraints are pretty solid and well founded here.
Another thing to note is that the from_raw
and into_raw
APIs might also want to return/accept implementation specific flags.
When I made this PR, I passed JIT
flag by default to the underlying implementations, as it is not known/indeterminate if the given memory region originally was intended with executing in mind (this could be customizable though). This in turn prevented the library-side restriction of setting pages as executable.
Anyway, to provide some more context/information: In my specific use case at least, the intention was to work with not only maps created by mmap-rs
specifically, but memory that was pre-mapped (such as binary code from [.exe/.elf etc.]); and mmap-rs
would work as a fallback for platforms without specific implementations (which delegate to (VirtualProtect
/mprotect
/<protect>
) etc.
Added: Ability to create Mmap unsafely from an existing address.
This PR extends the functionality of our memory-mapping library by allowing
Mmap
objects to be created from an existing, raw memory address. This feature has been added through the newMmapOptions::map_from_existing
API, which is unsafe and returns a platform-specificMmapMut
object.Lifetime Management
Memory-mapping objects created from raw addresses become 'owned' by the calling code.
This means that the lifetime of the mapped region is now managed by the
MmapMut
object, and dropping this object will cause the corresponding memory region to be unmapped.This is documented alongside the newly added
map_from_existing
API.Tests
A basic unit test was added. This test creates a new
MmapMut
object from an existing, unmanaged memory address and performs the following checks:Validates that the data at the memory-mapped object's address matches what is expected, ensuring that the raw address mapping is correctly established.
Checks that permission changes performed from one
Mmap
object are reflected in the otherMmap
object, validating that objects point to the same physical page.Use Case
I am in the process of porting a well known C# function hooking library to Rust (Work in Progress), while making it as portable as possible. (This means supporting non-x86 architectures and non-Windows OSes)
mmap-rs
supports more 'edge-case' platforms such as FreeBSD, Android and iOS; so for those platforms where testing is more difficult, I would prefer to leverage existing code, even if I wind up wasting some CPU cycles on Mmap object initialization for some more temporary actions (like temp changing permissions).Notes
Open to making any changes requested before merging; I'm still (relatively) new to Rust, so if I've missed anything here, please let me know.