@@ -53,7 +53,12 @@ mod mmap {
5353 | libc:: MADV_SEQUENTIAL
5454 | libc:: MADV_WILLNEED
5555 | libc:: MADV_DONTNEED => Ok ( advice) ,
56- #[ cfg( any( target_os = "linux" , target_os = "macos" , target_os = "ios" ) ) ]
56+ #[ cfg( any(
57+ target_os = "linux" ,
58+ target_os = "macos" ,
59+ target_os = "ios" ,
60+ target_os = "freebsd"
61+ ) ) ]
5762 libc:: MADV_FREE => Ok ( advice) ,
5863 #[ cfg( target_os = "linux" ) ]
5964 libc:: MADV_DONTFORK
@@ -66,6 +71,12 @@ mod mmap {
6671 | libc:: MADV_DONTDUMP
6772 | libc:: MADV_DODUMP
6873 | libc:: MADV_HWPOISON => Ok ( advice) ,
74+ #[ cfg( target_os = "freebsd" ) ]
75+ libc:: MADV_NOSYNC
76+ | libc:: MADV_AUTOSYNC
77+ | libc:: MADV_NOCORE
78+ | libc:: MADV_CORE
79+ | libc:: MADV_PROTECT => Ok ( advice) ,
6980 _ => Err ( vm. new_value_error ( "Not a valid Advice value" ) ) ,
7081 }
7182 }
@@ -96,7 +107,7 @@ mod mmap {
96107 #[ pyattr]
97108 use libc:: {
98109 MADV_DONTNEED , MADV_NORMAL , MADV_RANDOM , MADV_SEQUENTIAL , MADV_WILLNEED , MAP_ANON ,
99- MAP_ANONYMOUS , MAP_PRIVATE , MAP_SHARED , PROT_READ , PROT_WRITE ,
110+ MAP_ANONYMOUS , MAP_PRIVATE , MAP_SHARED , PROT_EXEC , PROT_READ , PROT_WRITE ,
100111 } ;
101112
102113 #[ cfg( target_os = "macos" ) ]
@@ -146,6 +157,16 @@ mod mmap {
146157 #[ pyattr]
147158 use libc:: { MAP_DENYWRITE , MAP_EXECUTABLE , MAP_POPULATE } ;
148159
160+ // MAP_STACK is available on Linux, OpenBSD, and NetBSD
161+ #[ cfg( any( target_os = "linux" , target_os = "openbsd" , target_os = "netbsd" ) ) ]
162+ #[ pyattr]
163+ use libc:: MAP_STACK ;
164+
165+ // FreeBSD-specific MADV constants
166+ #[ cfg( target_os = "freebsd" ) ]
167+ #[ pyattr]
168+ use libc:: { MADV_AUTOSYNC , MADV_CORE , MADV_NOCORE , MADV_NOSYNC , MADV_PROTECT } ;
169+
149170 #[ pyattr]
150171 const ACCESS_DEFAULT : u32 = AccessMode :: Default as u32 ;
151172 #[ pyattr]
@@ -404,6 +425,15 @@ mod mmap {
404425 } ;
405426
406427 let fd = unsafe { crt_fd:: Borrowed :: try_borrow_raw ( fd) } ;
428+
429+ // macOS: Issue #11277: fsync(2) is not enough on OS X - a special, OS X specific
430+ // fcntl(2) is necessary to force DISKSYNC and get around mmap(2) bug
431+ #[ cfg( target_os = "macos" ) ]
432+ if let Ok ( fd) = fd {
433+ use std:: os:: fd:: AsRawFd ;
434+ unsafe { libc:: fcntl ( fd. as_raw_fd ( ) , libc:: F_FULLFSYNC ) } ;
435+ }
436+
407437 if let Ok ( fd) = fd {
408438 let metadata = fstat ( fd)
409439 . map_err ( |err| io:: Error :: from_raw_os_error ( err as i32 ) . to_pyexception ( vm) ) ?;
@@ -538,7 +568,10 @@ mod mmap {
538568 map_size = ( file_len - offset) as usize ;
539569 } else {
540570 // If map_size > file_len, extend the file (Windows behavior)
541- let required_size = offset + map_size as i64 ;
571+ let required_size = offset. checked_add ( map_size as i64 ) . ok_or_else ( || {
572+ unsafe { CloseHandle ( duplicated_handle) } ;
573+ vm. new_overflow_error ( "mmap size would cause file size overflow" )
574+ } ) ?;
542575 if required_size > file_len {
543576 // Extend file using SetFilePointerEx + SetEndOfFile
544577 let result = unsafe {
@@ -799,8 +832,9 @@ mod mmap {
799832
800833 let sub = & options. sub ;
801834
835+ // returns start position for empty string
802836 if sub. is_empty ( ) {
803- return Ok ( PyInt :: from ( 0isize ) ) ;
837+ return Ok ( PyInt :: from ( start as isize ) ) ;
804838 }
805839
806840 let mmap = self . check_valid ( vm) ?;
@@ -815,8 +849,9 @@ mod mmap {
815849 let ( start, end) = self . get_find_range ( options. clone ( ) ) ;
816850
817851 let sub = & options. sub ;
852+ // returns start position for empty string
818853 if sub. is_empty ( ) {
819- return Ok ( PyInt :: from ( 0isize ) ) ;
854+ return Ok ( PyInt :: from ( start as isize ) ) ;
820855 }
821856
822857 let mmap = self . check_valid ( vm) ?;
@@ -850,18 +885,20 @@ mod mmap {
850885 #[ cfg( all( unix, not( target_os = "redox" ) ) ) ]
851886 #[ pymethod]
852887 fn madvise ( & self , options : AdviseOptions , vm : & VirtualMachine ) -> PyResult < ( ) > {
853- let ( option, _start , _length ) = options. values ( self . __len__ ( ) , vm) ?;
888+ let ( option, start , length ) = options. values ( self . __len__ ( ) , vm) ?;
854889 let advice = validate_advice ( vm, option) ?;
855890
856891 let guard = self . check_valid ( vm) ?;
857892 let mmap = guard. deref ( ) . as_ref ( ) . unwrap ( ) ;
858- let ( ptr, len ) = match mmap {
859- MmapObj :: Read ( m) => ( m. as_ptr ( ) , m . len ( ) ) ,
860- MmapObj :: Write ( m) => ( m. as_ptr ( ) , m . len ( ) ) ,
893+ let ptr = match mmap {
894+ MmapObj :: Read ( m) => m. as_ptr ( ) ,
895+ MmapObj :: Write ( m) => m. as_ptr ( ) ,
861896 } ;
862897
863- // Call libc::madvise directly
864- let result = unsafe { libc:: madvise ( ptr as * mut libc:: c_void , len, advice) } ;
898+ // Apply madvise to the specified range (start, length)
899+ let ptr_with_offset = unsafe { ptr. add ( start) } ;
900+ let result =
901+ unsafe { libc:: madvise ( ptr_with_offset as * mut libc:: c_void , length, advice) } ;
865902 if result != 0 {
866903 return Err ( io:: Error :: last_os_error ( ) . to_pyexception ( vm) ) ;
867904 }
@@ -1062,30 +1099,14 @@ mod mmap {
10621099 if result == 0 {
10631100 // Restore original mmap on error
10641101 let err = io:: Error :: last_os_error ( ) ;
1065- let old_size = self . size . load ( ) ;
1066- if let Ok ( mmap) = Self :: create_mmap_windows (
1067- handle as HANDLE ,
1068- self . offset ,
1069- old_size,
1070- & self . access ,
1071- ) {
1072- * mmap_guard = Some ( mmap) ;
1073- }
1102+ self . try_restore_mmap ( & mut mmap_guard, handle as HANDLE , self . size . load ( ) ) ;
10741103 return Err ( err. to_pyexception ( vm) ) ;
10751104 }
10761105
10771106 let result = unsafe { SetEndOfFile ( handle as HANDLE ) } ;
10781107 if result == 0 {
10791108 let err = io:: Error :: last_os_error ( ) ;
1080- let old_size = self . size . load ( ) ;
1081- if let Ok ( mmap) = Self :: create_mmap_windows (
1082- handle as HANDLE ,
1083- self . offset ,
1084- old_size,
1085- & self . access ,
1086- ) {
1087- * mmap_guard = Some ( mmap) ;
1088- }
1109+ self . try_restore_mmap ( & mut mmap_guard, handle as HANDLE , self . size . load ( ) ) ;
10891110 return Err ( err. to_pyexception ( vm) ) ;
10901111 }
10911112
@@ -1248,6 +1269,12 @@ mod mmap {
12481269 fn __exit__ ( zelf : & Py < Self > , _args : FuncArgs , vm : & VirtualMachine ) -> PyResult < ( ) > {
12491270 zelf. close ( vm)
12501271 }
1272+
1273+ #[ cfg( windows) ]
1274+ #[ pymethod]
1275+ fn __sizeof__ ( & self ) -> usize {
1276+ std:: mem:: size_of :: < Self > ( )
1277+ }
12511278 }
12521279
12531280 impl PyMmap {
@@ -1281,6 +1308,17 @@ mod mmap {
12811308 result
12821309 }
12831310
1311+ /// Try to restore mmap after a failed resize operation.
1312+ /// Returns true if restoration succeeded, false otherwise.
1313+ /// If restoration fails, marks the mmap as closed.
1314+ #[ cfg( windows) ]
1315+ fn try_restore_mmap ( & self , mmap_guard : & mut Option < MmapObj > , handle : HANDLE , size : usize ) {
1316+ match Self :: create_mmap_windows ( handle, self . offset , size, & self . access ) {
1317+ Ok ( mmap) => * mmap_guard = Some ( mmap) ,
1318+ Err ( _) => self . closed . store ( true ) ,
1319+ }
1320+ }
1321+
12841322 fn getitem_by_index ( & self , i : isize , vm : & VirtualMachine ) -> PyResult < PyObjectRef > {
12851323 let i = i
12861324 . wrapped_at ( self . __len__ ( ) )
0 commit comments