1+ use cranelift_module:: { ModuleError , ModuleResult } ;
2+
3+ #[ cfg( all( not( target_os = "windows" ) , feature = "selinux-fix" ) ) ]
4+ use memmap2:: MmapMut ;
5+
6+ #[ cfg( not( any( feature = "selinux-fix" , windows) ) ) ]
7+ use std:: alloc;
18use std:: io;
29use std:: mem;
310use std:: ptr;
411
5- use cranelift_module:: { ModuleError , ModuleResult } ;
6- use memmap2:: MmapMut ;
7-
812use super :: { BranchProtection , JITMemoryKind , JITMemoryProvider } ;
913
1014/// A simple struct consisting of a pointer and length.
1115struct PtrLen {
16+ #[ cfg( all( not( target_os = "windows" ) , feature = "selinux-fix" ) ) ]
1217 map : Option < MmapMut > ,
18+
1319 ptr : * mut u8 ,
1420 len : usize ,
1521}
@@ -18,14 +24,17 @@ impl PtrLen {
1824 /// Create a new empty `PtrLen`.
1925 fn new ( ) -> Self {
2026 Self {
27+ #[ cfg( all( not( target_os = "windows" ) , feature = "selinux-fix" ) ) ]
2128 map : None ,
29+
2230 ptr : ptr:: null_mut ( ) ,
2331 len : 0 ,
2432 }
2533 }
2634
2735 /// Create a new `PtrLen` pointing to at least `size` bytes of memory,
2836 /// suitably sized and aligned for memory protection.
37+ #[ cfg( all( not( target_os = "windows" ) , feature = "selinux-fix" ) ) ]
2938 fn with_size ( size : usize ) -> io:: Result < Self > {
3039 let alloc_size = region:: page:: ceil ( size as * const ( ) ) as usize ;
3140 MmapMut :: map_anon ( alloc_size) . map ( |mut mmap| {
@@ -38,8 +47,70 @@ impl PtrLen {
3847 }
3948 } )
4049 }
50+
51+ #[ cfg( all( not( target_os = "windows" ) , not( feature = "selinux-fix" ) ) ) ]
52+ fn with_size ( size : usize ) -> io:: Result < Self > {
53+ assert_ne ! ( size, 0 ) ;
54+ let page_size = region:: page:: size ( ) ;
55+ let alloc_size = region:: page:: ceil ( size as * const ( ) ) as usize ;
56+ let layout = alloc:: Layout :: from_size_align ( alloc_size, page_size) . unwrap ( ) ;
57+ // Safety: We assert that the size is non-zero above.
58+ let ptr = unsafe { alloc:: alloc ( layout) } ;
59+
60+ if !ptr. is_null ( ) {
61+ Ok ( Self {
62+ ptr,
63+ len : alloc_size,
64+ } )
65+ } else {
66+ Err ( io:: Error :: from ( io:: ErrorKind :: OutOfMemory ) )
67+ }
68+ }
69+
70+ #[ cfg( target_os = "windows" ) ]
71+ fn with_size ( size : usize ) -> io:: Result < Self > {
72+ use windows_sys:: Win32 :: System :: Memory :: {
73+ MEM_COMMIT , MEM_RESERVE , PAGE_READWRITE , VirtualAlloc ,
74+ } ;
75+
76+ // VirtualAlloc always rounds up to the next multiple of the page size
77+ let ptr = unsafe {
78+ VirtualAlloc (
79+ ptr:: null_mut ( ) ,
80+ size,
81+ MEM_COMMIT | MEM_RESERVE ,
82+ PAGE_READWRITE ,
83+ )
84+ } ;
85+ if !ptr. is_null ( ) {
86+ Ok ( Self {
87+ ptr : ptr as * mut u8 ,
88+ len : region:: page:: ceil ( size as * const ( ) ) as usize ,
89+ } )
90+ } else {
91+ Err ( io:: Error :: last_os_error ( ) )
92+ }
93+ }
4194}
4295
96+ // `MMapMut` from `cfg(feature = "selinux-fix")` already deallocates properly.
97+ #[ cfg( all( not( target_os = "windows" ) , not( feature = "selinux-fix" ) ) ) ]
98+ impl Drop for PtrLen {
99+ fn drop ( & mut self ) {
100+ if !self . ptr . is_null ( ) {
101+ let page_size = region:: page:: size ( ) ;
102+ let layout = alloc:: Layout :: from_size_align ( self . len , page_size) . unwrap ( ) ;
103+ unsafe {
104+ region:: protect ( self . ptr , self . len , region:: Protection :: READ_WRITE )
105+ . expect ( "unable to unprotect memory" ) ;
106+ alloc:: dealloc ( self . ptr , layout)
107+ }
108+ }
109+ }
110+ }
111+
112+ // TODO: add a `Drop` impl for `cfg(target_os = "windows")`
113+
43114/// JIT memory manager. This manages pages of suitably aligned and
44115/// accessible memory. Memory will be leaked by default to have
45116/// function pointers remain valid for the remainder of the
@@ -130,9 +201,13 @@ impl Memory {
130201
131202 /// Iterates non protected memory allocations that are of not zero bytes in size.
132203 fn non_protected_allocations_iter ( & self ) -> impl Iterator < Item = & PtrLen > {
133- self . allocations [ self . already_protected ..]
134- . iter ( )
135- . filter ( |& PtrLen { map, len, .. } | * len != 0 && map. is_some ( ) )
204+ let iter = self . allocations [ self . already_protected ..] . iter ( ) ;
205+
206+ #[ cfg( all( not( target_os = "windows" ) , feature = "selinux-fix" ) ) ]
207+ return iter. filter ( |& PtrLen { map, len, .. } | * len != 0 && map. is_some ( ) ) ;
208+
209+ #[ cfg( any( target_os = "windows" , not( feature = "selinux-fix" ) ) ) ]
210+ return iter. filter ( |& PtrLen { len, .. } | * len != 0 ) ;
136211 }
137212
138213 /// Frees all allocated memory regions that would be leaked otherwise.
0 commit comments