1
1
//! Copy-on-write initialization support: creation of backing images for
2
2
//! modules, and logic to support mapping these backing images into memory.
3
3
4
+ #![ cfg_attr( not( unix) , allow( unused_imports, unused_variables) ) ]
5
+
4
6
use crate :: InstantiationError ;
5
7
use crate :: MmapVec ;
6
8
use anyhow:: Result ;
7
9
use libc:: c_void;
8
- use rustix:: fd:: AsRawFd ;
9
10
use std:: fs:: File ;
10
11
use std:: sync:: Arc ;
11
12
use std:: { convert:: TryFrom , ops:: Range } ;
@@ -60,24 +61,34 @@ pub struct MemoryImage {
60
61
61
62
#[ derive( Debug ) ]
62
63
enum FdSource {
64
+ #[ cfg( unix) ]
63
65
Mmap ( Arc < File > ) ,
64
66
#[ cfg( target_os = "linux" ) ]
65
67
Memfd ( memfd:: Memfd ) ,
66
68
}
67
69
68
70
impl FdSource {
71
+ #[ cfg( unix) ]
69
72
fn as_file ( & self ) -> & File {
70
73
match self {
71
- FdSource :: Mmap ( file) => file,
74
+ FdSource :: Mmap ( ref file) => file,
72
75
#[ cfg( target_os = "linux" ) ]
73
- FdSource :: Memfd ( memfd) => memfd. as_file ( ) ,
76
+ FdSource :: Memfd ( ref memfd) => memfd. as_file ( ) ,
74
77
}
75
78
}
76
79
}
77
80
78
81
impl PartialEq for FdSource {
79
82
fn eq ( & self , other : & FdSource ) -> bool {
80
- self . as_file ( ) . as_raw_fd ( ) == other. as_file ( ) . as_raw_fd ( )
83
+ cfg_if:: cfg_if! {
84
+ if #[ cfg( unix) ] {
85
+ use rustix:: fd:: AsRawFd ;
86
+ self . as_file( ) . as_raw_fd( ) == other. as_file( ) . as_raw_fd( )
87
+ } else {
88
+ drop( other) ;
89
+ match * self { }
90
+ }
91
+ }
81
92
}
82
93
}
83
94
@@ -111,6 +122,7 @@ impl MemoryImage {
111
122
// files, but for now this is still a Linux-specific region of Wasmtime.
112
123
// Some work will be needed to get this file compiling for macOS and
113
124
// Windows.
125
+ #[ cfg( not( windows) ) ]
114
126
if let Some ( mmap) = mmap {
115
127
let start = mmap. as_ptr ( ) as usize ;
116
128
let end = start + mmap. len ( ) ;
@@ -185,6 +197,42 @@ impl MemoryImage {
185
197
}
186
198
}
187
199
}
200
+
201
+ unsafe fn map_at ( & self , base : usize ) -> Result < ( ) > {
202
+ cfg_if:: cfg_if! {
203
+ if #[ cfg( unix) ] {
204
+ let ptr = rustix:: mm:: mmap(
205
+ ( base + self . linear_memory_offset) as * mut c_void,
206
+ self . len,
207
+ rustix:: mm:: ProtFlags :: READ | rustix:: mm:: ProtFlags :: WRITE ,
208
+ rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
209
+ self . fd. as_file( ) ,
210
+ self . fd_offset,
211
+ ) ?;
212
+ assert_eq!( ptr as usize , base + self . linear_memory_offset) ;
213
+ Ok ( ( ) )
214
+ } else {
215
+ match self . fd { }
216
+ }
217
+ }
218
+ }
219
+
220
+ unsafe fn remap_as_zeros_at ( & self , base : usize ) -> Result < ( ) > {
221
+ cfg_if:: cfg_if! {
222
+ if #[ cfg( unix) ] {
223
+ let ptr = rustix:: mm:: mmap_anonymous(
224
+ ( base + self . linear_memory_offset) as * mut c_void,
225
+ self . len,
226
+ rustix:: mm:: ProtFlags :: READ | rustix:: mm:: ProtFlags :: WRITE ,
227
+ rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
228
+ ) ?;
229
+ assert_eq!( ptr as usize , base + self . linear_memory_offset) ;
230
+ Ok ( ( ) )
231
+ } else {
232
+ match self . fd { }
233
+ }
234
+ }
235
+ }
188
236
}
189
237
190
238
#[ cfg( target_os = "linux" ) ]
@@ -374,6 +422,17 @@ impl MemoryImageSlot {
374
422
}
375
423
}
376
424
425
+ pub ( crate ) fn dummy ( ) -> MemoryImageSlot {
426
+ MemoryImageSlot {
427
+ base : 0 ,
428
+ static_size : 0 ,
429
+ image : None ,
430
+ accessible : 0 ,
431
+ dirty : false ,
432
+ clear_on_drop : false ,
433
+ }
434
+ }
435
+
377
436
/// Inform the MemoryImageSlot that it should *not* clear the underlying
378
437
/// address space when dropped. This should be used only when the
379
438
/// caller will clear or reuse the address space in some other
@@ -396,10 +455,7 @@ impl MemoryImageSlot {
396
455
}
397
456
398
457
// Otherwise use `mprotect` to make the new pages read/write.
399
- self . set_protection (
400
- self . accessible ..size_bytes,
401
- rustix:: mm:: MprotectFlags :: READ | rustix:: mm:: MprotectFlags :: WRITE ,
402
- ) ?;
458
+ self . set_protection ( self . accessible ..size_bytes, true ) ?;
403
459
self . accessible = size_bytes;
404
460
405
461
Ok ( ( ) )
@@ -444,14 +500,9 @@ impl MemoryImageSlot {
444
500
if self . image . as_ref ( ) != maybe_image {
445
501
if let Some ( image) = & self . image {
446
502
unsafe {
447
- let ptr = rustix:: mm:: mmap_anonymous (
448
- ( self . base + image. linear_memory_offset ) as * mut c_void ,
449
- image. len ,
450
- rustix:: mm:: ProtFlags :: READ | rustix:: mm:: ProtFlags :: WRITE ,
451
- rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
452
- )
453
- . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
454
- assert_eq ! ( ptr as usize , self . base + image. linear_memory_offset) ;
503
+ image
504
+ . remap_as_zeros_at ( self . base )
505
+ . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
455
506
}
456
507
self . image = None ;
457
508
}
@@ -461,11 +512,8 @@ impl MemoryImageSlot {
461
512
// appropriate. First up is to grow the read/write portion of memory if
462
513
// it's not large enough to accommodate `initial_size_bytes`.
463
514
if self . accessible < initial_size_bytes {
464
- self . set_protection (
465
- self . accessible ..initial_size_bytes,
466
- rustix:: mm:: MprotectFlags :: READ | rustix:: mm:: MprotectFlags :: WRITE ,
467
- )
468
- . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
515
+ self . set_protection ( self . accessible ..initial_size_bytes, true )
516
+ . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
469
517
self . accessible = initial_size_bytes;
470
518
}
471
519
@@ -480,11 +528,8 @@ impl MemoryImageSlot {
480
528
if initial_size_bytes < self . accessible {
481
529
match style {
482
530
MemoryStyle :: Static { .. } => {
483
- self . set_protection (
484
- initial_size_bytes..self . accessible ,
485
- rustix:: mm:: MprotectFlags :: empty ( ) ,
486
- )
487
- . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
531
+ self . set_protection ( initial_size_bytes..self . accessible , false )
532
+ . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
488
533
self . accessible = initial_size_bytes;
489
534
}
490
535
MemoryStyle :: Dynamic { .. } => { }
@@ -503,16 +548,9 @@ impl MemoryImageSlot {
503
548
) ;
504
549
if image. len > 0 {
505
550
unsafe {
506
- let ptr = rustix:: mm:: mmap (
507
- ( self . base + image. linear_memory_offset ) as * mut c_void ,
508
- image. len ,
509
- rustix:: mm:: ProtFlags :: READ | rustix:: mm:: ProtFlags :: WRITE ,
510
- rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
511
- image. fd . as_file ( ) ,
512
- image. fd_offset ,
513
- )
514
- . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
515
- assert_eq ! ( ptr as usize , self . base + image. linear_memory_offset) ;
551
+ image
552
+ . map_at ( self . base )
553
+ . map_err ( |e| InstantiationError :: Resource ( e. into ( ) ) ) ?;
516
554
}
517
555
}
518
556
}
@@ -675,13 +713,35 @@ impl MemoryImageSlot {
675
713
}
676
714
}
677
715
678
- fn set_protection ( & self , range : Range < usize > , flags : rustix :: mm :: MprotectFlags ) -> Result < ( ) > {
716
+ fn set_protection ( & self , range : Range < usize > , readwrite : bool ) -> Result < ( ) > {
679
717
assert ! ( range. start <= range. end) ;
680
718
assert ! ( range. end <= self . static_size) ;
681
- let mprotect_start = self . base . checked_add ( range. start ) . unwrap ( ) ;
682
- if range. len ( ) > 0 {
683
- unsafe {
684
- rustix:: mm:: mprotect ( mprotect_start as * mut _ , range. len ( ) , flags) ?;
719
+ let start = self . base . checked_add ( range. start ) . unwrap ( ) ;
720
+ if range. len ( ) == 0 {
721
+ return Ok ( ( ) ) ;
722
+ }
723
+
724
+ unsafe {
725
+ cfg_if:: cfg_if! {
726
+ if #[ cfg( unix) ] {
727
+ let flags = if readwrite {
728
+ rustix:: mm:: MprotectFlags :: READ | rustix:: mm:: MprotectFlags :: WRITE
729
+ } else {
730
+ rustix:: mm:: MprotectFlags :: empty( )
731
+ } ;
732
+ rustix:: mm:: mprotect( start as * mut _, range. len( ) , flags) ?;
733
+ } else {
734
+ use windows_sys:: Win32 :: System :: Memory :: * ;
735
+
736
+ let failure = if readwrite {
737
+ VirtualAlloc ( start as _, range. len( ) , MEM_COMMIT , PAGE_READWRITE ) . is_null( )
738
+ } else {
739
+ VirtualFree ( start as _, range. len( ) , MEM_DECOMMIT ) == 0
740
+ } ;
741
+ if failure {
742
+ return Err ( std:: io:: Error :: last_os_error( ) . into( ) ) ;
743
+ }
744
+ }
685
745
}
686
746
}
687
747
@@ -701,13 +761,22 @@ impl MemoryImageSlot {
701
761
/// inaccessible. Used both during instantiate and during drop.
702
762
fn reset_with_anon_memory ( & mut self ) -> Result < ( ) > {
703
763
unsafe {
704
- let ptr = rustix:: mm:: mmap_anonymous (
705
- self . base as * mut c_void ,
706
- self . static_size ,
707
- rustix:: mm:: ProtFlags :: empty ( ) ,
708
- rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
709
- ) ?;
710
- assert_eq ! ( ptr as usize , self . base) ;
764
+ cfg_if:: cfg_if! {
765
+ if #[ cfg( unix) ] {
766
+ let ptr = rustix:: mm:: mmap_anonymous(
767
+ self . base as * mut c_void,
768
+ self . static_size,
769
+ rustix:: mm:: ProtFlags :: empty( ) ,
770
+ rustix:: mm:: MapFlags :: PRIVATE | rustix:: mm:: MapFlags :: FIXED ,
771
+ ) ?;
772
+ assert_eq!( ptr as usize , self . base) ;
773
+ } else {
774
+ use windows_sys:: Win32 :: System :: Memory :: * ;
775
+ if VirtualFree ( self . base as _, self . static_size, MEM_DECOMMIT ) == 0 {
776
+ return Err ( std:: io:: Error :: last_os_error( ) . into( ) ) ;
777
+ }
778
+ }
779
+ }
711
780
}
712
781
713
782
self . image = None ;
0 commit comments