@@ -199,7 +199,6 @@ mod mmap {
199199 pos : AtomicCell < usize > , // relative to offset
200200 exports : AtomicCell < usize > ,
201201 access : AccessMode ,
202- #[ cfg( unix) ]
203202 trackfd : bool ,
204203 #[ cfg( target_os = "linux" ) ]
205204 anonymous : bool ,
@@ -263,6 +262,8 @@ mod mmap {
263262 access : AccessMode ,
264263 #[ pyarg( any, default ) ]
265264 offset : i64 ,
265+ #[ pyarg( named, default = true ) ]
266+ trackfd : bool ,
266267 }
267268
268269 impl MmapNewArgs {
@@ -509,6 +510,7 @@ mod mmap {
509510 tagname,
510511 access,
511512 offset,
513+ trackfd,
512514 ..
513515 } = args;
514516
@@ -589,8 +591,9 @@ mod mmap {
589591 }
590592 }
591593
592- // When tagname is provided, use raw Win32 APIs for named shared memory
593- if let Some ( ref tag) = tag_str {
594+ // memmap2 retains a duplicated file handle, so untracked mappings
595+ // must use Win32 directly as well as named shared memory mappings.
596+ if tag_str. is_some ( ) || !trackfd {
594597 let fh = if let Some ( fh) = fh {
595598 // Close the duplicated handle - we'll use the original
596599 // file handle for CreateFileMappingW
@@ -602,9 +605,9 @@ mod mmap {
602605 host_mmap:: INVALID_HANDLE
603606 } ;
604607
605- let named = host_mmap:: create_named_mapping (
608+ let named = host_mmap:: create_mapping (
606609 fh,
607- tag ,
610+ tag_str . as_deref ( ) ,
608611 match access {
609612 AccessMode :: Default => host_mmap:: AccessMode :: Default ,
610613 AccessMode :: Read => host_mmap:: AccessMode :: Read ,
@@ -631,12 +634,16 @@ mod mmap {
631634 pos : AtomicCell :: new ( 0 ) ,
632635 exports : AtomicCell :: new ( 0 ) ,
633636 access,
637+ trackfd,
634638 } ) ;
635639 }
636640
637641 let ( handle, mmap) = if duplicated_handle != host_mmap:: INVALID_HANDLE {
638642 let mmap = Self :: create_mmap_windows ( duplicated_handle, offset, map_size, & access)
639- . map_err ( |e| e. to_pyexception ( vm) ) ?;
643+ . map_err ( |e| {
644+ host_mmap:: close_handle ( duplicated_handle) ;
645+ e. to_pyexception ( vm)
646+ } ) ?;
640647 ( duplicated_handle as isize , mmap)
641648 } else {
642649 // Anonymous mapping
@@ -653,6 +660,7 @@ mod mmap {
653660 pos : AtomicCell :: new ( 0 ) ,
654661 exports : AtomicCell :: new ( 0 ) ,
655662 access,
663+ trackfd,
656664 } )
657665 }
658666 }
@@ -812,7 +820,6 @@ mod mmap {
812820 return Err ( vm. new_buffer_error ( "mmap can't resize with extant buffers exported." ) ) ;
813821 }
814822
815- #[ cfg( unix) ]
816823 if !self . trackfd {
817824 drop ( mmap) ;
818825 return Err ( vm. new_value_error ( "mmap can't resize with trackfd=False." ) ) ;
@@ -1312,6 +1319,9 @@ mod mmap {
13121319 #[ pymethod]
13131320 fn size ( zelf : & Py < Self > , vm : & VirtualMachine ) -> PyResult < PyIntRef > {
13141321 let _mmap = zelf. check_valid ( vm) ?;
1322+ if !zelf. trackfd {
1323+ return Err ( vm. new_value_error ( "can't get size with trackfd=False" ) ) ;
1324+ }
13151325 let handle = zelf. handle . load ( ) ;
13161326 if host_mmap:: is_invalid_handle_value ( handle) {
13171327 // Anonymous mapping, return the mmap size
@@ -1642,6 +1652,29 @@ mod mmap {
16421652 rejects_borrowed_buffer ( false ) ;
16431653 }
16441654
1655+ #[ cfg( windows) ]
1656+ #[ test]
1657+ fn untracked_mapping_cannot_resize ( ) {
1658+ crate :: vm:: Interpreter :: without_stdlib ( Default :: default ( ) ) . enter ( |vm| {
1659+ let mapped = PyMmap :: py_new (
1660+ vm. ctx . types . type_type ,
1661+ MmapNewArgs {
1662+ fileno : -1 ,
1663+ length : 64 ,
1664+ tagname : None ,
1665+ access : AccessMode :: Default ,
1666+ offset : 0 ,
1667+ trackfd : false ,
1668+ } ,
1669+ vm,
1670+ )
1671+ . unwrap ( ) ;
1672+ assert_eq ! ( mapped. __len__( ) , 64 ) ;
1673+ assert ! ( !mapped. trackfd) ;
1674+ assert ! ( mapped. check_resizeable( vm) . is_err( ) ) ;
1675+ } ) ;
1676+ }
1677+
16451678 #[ test]
16461679 fn resize_rejects_borrowed_buffer ( ) {
16471680 rejects_borrowed_buffer ( true ) ;
0 commit comments