11use crate :: prelude:: * ;
2- #[ cfg( not( has_virtual_memory) ) ]
32use crate :: runtime:: vm:: send_sync_ptr:: SendSyncPtr ;
43#[ cfg( has_virtual_memory) ]
54use crate :: runtime:: vm:: { mmap:: UnalignedLength , Mmap } ;
65#[ cfg( not( has_virtual_memory) ) ]
76use alloc:: alloc:: Layout ;
87use alloc:: sync:: Arc ;
98use core:: ops:: { Deref , Range } ;
10- #[ cfg( not( has_virtual_memory) ) ]
119use core:: ptr:: NonNull ;
1210#[ cfg( feature = "std" ) ]
1311use std:: fs:: File ;
@@ -40,6 +38,8 @@ pub enum MmapVec {
4038 layout : Layout ,
4139 } ,
4240 #[ doc( hidden) ]
41+ ExternallyOwned { memory : SendSyncPtr < [ u8 ] > } ,
42+ #[ doc( hidden) ]
4343 #[ cfg( has_virtual_memory) ]
4444 Mmap {
4545 mmap : Mmap < UnalignedLength > ,
@@ -74,6 +74,11 @@ impl MmapVec {
7474 MmapVec :: Alloc { base, layout }
7575 }
7676
77+ fn new_externally_owned ( memory : NonNull < [ u8 ] > ) -> MmapVec {
78+ let memory = SendSyncPtr :: new ( memory) ;
79+ MmapVec :: ExternallyOwned { memory }
80+ }
81+
7782 /// Creates a new zero-initialized `MmapVec` with the given `size`
7883 /// and `alignment`.
7984 ///
@@ -101,6 +106,25 @@ impl MmapVec {
101106 MmapVec :: from_slice_with_alignment ( slice, 1 )
102107 }
103108
109+ /// Creates a new `MmapVec` from an existing memory region
110+ ///
111+ /// This method avoids the copy performed by [`Self::from_slice`] by
112+ /// directly using the memory region provided. This must be done with
113+ /// extreme care, however, as any concurrent modification of the provided
114+ /// memory will cause undefined and likely very, very bad things to
115+ /// happen.
116+ ///
117+ /// The memory provided is guaranteed to not be mutated by the runtime.
118+ ///
119+ /// # Safety
120+ ///
121+ /// As there is no copy here, the runtime will be making direct readonly use
122+ /// of the provided memory. As such, outside writes to this memory region
123+ /// will result in undefined and likely very undesirable behavior.
124+ pub unsafe fn from_raw ( memory : NonNull < [ u8 ] > ) -> Result < MmapVec > {
125+ Ok ( MmapVec :: new_externally_owned ( memory) )
126+ }
127+
104128 /// Creates a new `MmapVec` from the contents of an existing
105129 /// `slice`, with a minimum alignment.
106130 ///
@@ -110,7 +134,7 @@ impl MmapVec {
110134 ///
111135 /// A new `MmapVec` is allocated to hold the contents of `slice` and then
112136 /// `slice` is copied into the new mmap. It's recommended to avoid this
113- /// method if possible to avoid the need to copy data around. pub
137+ /// method if possible to avoid the need to copy data around.
114138 pub fn from_slice_with_alignment ( slice : & [ u8 ] , align : usize ) -> Result < MmapVec > {
115139 let mut result = MmapVec :: with_capacity_and_alignment ( slice. len ( ) , align) ?;
116140 // SAFETY: The mmap hasn't been made readonly yet so this should be
@@ -121,6 +145,37 @@ impl MmapVec {
121145 Ok ( result)
122146 }
123147
148+ /// Return `true` if the `MmapVec` suport virtual memory operations
149+ ///
150+ /// In some cases, such as when using externally owned memory, the underlying
151+ /// platform may support virtual memory but it still may not be legal
152+ /// to perform virtual memory operations on this memory.
153+ pub fn supports_virtual_memory ( & self ) -> bool {
154+ match self {
155+ #[ cfg( has_virtual_memory) ]
156+ MmapVec :: Mmap { .. } => true ,
157+ MmapVec :: ExternallyOwned { .. } => false ,
158+ #[ cfg( not( has_virtual_memory) ) ]
159+ MmapVec :: Alloc { .. } => false ,
160+ }
161+ }
162+
163+ /// Return true if this `MmapVec` is always readonly
164+ ///
165+ /// Attempting to get access to mutate readonly memory via
166+ /// [`MmapVec::as_mut`] will result in a panic. Note that this method
167+ /// does not change with runtime changes to portions of the code memory
168+ /// via `MmapVec::make_readonly` for platforms with virtual memory.
169+ pub fn is_always_readonly ( & self ) -> bool {
170+ match self {
171+ #[ cfg( has_virtual_memory) ]
172+ MmapVec :: Mmap { .. } => false ,
173+ MmapVec :: ExternallyOwned { .. } => true ,
174+ #[ cfg( not( has_virtual_memory) ) ]
175+ MmapVec :: Alloc { .. } => false ,
176+ }
177+ }
178+
124179 /// Creates a new `MmapVec` which is the given `File` mmap'd into memory.
125180 ///
126181 /// This function will determine the file's size and map the full contents
@@ -148,6 +203,9 @@ impl MmapVec {
148203 ) -> Result < ( ) > {
149204 let ( mmap, len) = match self {
150205 MmapVec :: Mmap { mmap, len } => ( mmap, * len) ,
206+ MmapVec :: ExternallyOwned { .. } => {
207+ bail ! ( "Unable to make externally owned memory executable" ) ;
208+ }
151209 } ;
152210 assert ! ( range. start <= range. end) ;
153211 assert ! ( range. end <= len) ;
@@ -159,6 +217,9 @@ impl MmapVec {
159217 pub unsafe fn make_readonly ( & self , range : Range < usize > ) -> Result < ( ) > {
160218 let ( mmap, len) = match self {
161219 MmapVec :: Mmap { mmap, len } => ( mmap, * len) ,
220+ MmapVec :: ExternallyOwned { .. } => {
221+ bail ! ( "Unable to make externally owned memory readonly" ) ;
222+ }
162223 } ;
163224 assert ! ( range. start <= range. end) ;
164225 assert ! ( range. end <= len) ;
@@ -171,6 +232,7 @@ impl MmapVec {
171232 match self {
172233 #[ cfg( not( has_virtual_memory) ) ]
173234 MmapVec :: Alloc { .. } => None ,
235+ MmapVec :: ExternallyOwned { .. } => None ,
174236 #[ cfg( has_virtual_memory) ]
175237 MmapVec :: Mmap { mmap, .. } => mmap. original_file ( ) ,
176238 }
@@ -189,13 +251,21 @@ impl MmapVec {
189251 /// # Unsafety
190252 ///
191253 /// This method is only safe if `make_readonly` hasn't been called yet to
192- /// ensure that the memory is indeed writable
254+ /// ensure that the memory is indeed writable. For a MmapVec created from
255+ /// a raw pointer using this memory as mutable is only safe if there are
256+ /// no outside reads or writes to the memory region.
257+ ///
258+ /// Externally owned code is implicitly considered to be readonly and this
259+ /// code will panic if called on externally owned memory.
193260 pub unsafe fn as_mut_slice ( & mut self ) -> & mut [ u8 ] {
194261 match self {
195262 #[ cfg( not( has_virtual_memory) ) ]
196263 MmapVec :: Alloc { base, layout } => {
197264 core:: slice:: from_raw_parts_mut ( base. as_mut ( ) , layout. size ( ) )
198265 }
266+ MmapVec :: ExternallyOwned { .. } => {
267+ panic ! ( "Mutating externally owned memory is prohibited" ) ;
268+ }
199269 #[ cfg( has_virtual_memory) ]
200270 MmapVec :: Mmap { mmap, len } => mmap. slice_mut ( 0 ..* len) ,
201271 }
@@ -212,6 +282,7 @@ impl Deref for MmapVec {
212282 MmapVec :: Alloc { base, layout } => unsafe {
213283 core:: slice:: from_raw_parts ( base. as_ptr ( ) , layout. size ( ) )
214284 } ,
285+ MmapVec :: ExternallyOwned { memory } => unsafe { memory. as_ref ( ) } ,
215286 #[ cfg( has_virtual_memory) ]
216287 MmapVec :: Mmap { mmap, len } => {
217288 // SAFETY: all bytes for this mmap, which is owned by
@@ -229,6 +300,9 @@ impl Drop for MmapVec {
229300 MmapVec :: Alloc { base, layout, .. } => unsafe {
230301 alloc:: alloc:: dealloc ( base. as_mut ( ) , layout. clone ( ) ) ;
231302 } ,
303+ MmapVec :: ExternallyOwned { .. } => {
304+ // Memory is allocated externally, nothing to do
305+ }
232306 #[ cfg( has_virtual_memory) ]
233307 MmapVec :: Mmap { .. } => {
234308 // Drop impl on the `mmap` takes care of this case.
0 commit comments