@@ -1127,51 +1127,108 @@ mod tests {
11271127 assert_eq ! ( data, ret_vec) ;
11281128 }
11291129
1130- /// A test to ensure that, if a `SharedMem` instance is cloned
1131- /// and _all_ clones are dropped, the memory region will no longer
1132- /// be valid.
1133- ///
1134- /// This test is ignored because it is incompatible with other tests as
1135- /// they may be allocating memory at the same time.
1136- ///
1137- /// Marking this test as ignored means that running `cargo test` will not
1138- /// run it. This feature will allow a developer who runs that command
1139- /// from their workstation to be successful without needing to know about
1140- /// test interdependencies. This test will, however, be run explicitly as a
1141- /// part of the CI pipeline.
1130+ /// Makes sure drop actually frees the underlying memory
11421131 #[ test]
1143- #[ ignore]
1144- #[ cfg( target_os = "linux" ) ]
11451132 fn test_drop ( ) {
1146- use proc_maps:: maps_contain_addr;
1147-
1148- let pid = std:: process:: id ( ) ;
1149-
11501133 let eshm = ExclusiveSharedMemory :: new ( PAGE_SIZE_USIZE ) . unwrap ( ) ;
11511134 let ( hshm1, gshm) = eshm. build ( ) ;
11521135 let hshm2 = hshm1. clone ( ) ;
1153- let addr = hshm1. raw_ptr ( ) as usize ;
1154-
1155- // ensure the address is in the process's virtual memory
1156- let maps_before_drop = proc_maps:: get_process_maps ( pid. try_into ( ) . unwrap ( ) ) . unwrap ( ) ;
1157- assert ! (
1158- maps_contain_addr( addr, & maps_before_drop) ,
1159- "shared memory address {:#x} was not found in process map, but should be" ,
1160- addr,
1161- ) ;
1162- // drop both shared memory instances, which should result
1136+ let addr = hshm1. raw_ptr ( ) ;
1137+ let size = hshm1. raw_mem_size ( ) ;
1138+
1139+ // Verify memory is initially accessible
1140+ #[ cfg( target_os = "linux" ) ]
1141+ {
1142+ let result =
1143+ unsafe { libc:: madvise ( addr as * mut libc:: c_void , size, libc:: MADV_NORMAL ) } ;
1144+ assert_eq ! (
1145+ result,
1146+ 0 ,
1147+ "Memory should be accessible before drop - madvise failed with errno: {}" ,
1148+ std:: io:: Error :: last_os_error( ) . raw_os_error( ) . unwrap( )
1149+ ) ;
1150+ }
1151+
1152+ #[ cfg( target_os = "windows" ) ]
1153+ {
1154+ use windows:: Win32 :: System :: Memory :: {
1155+ MEM_FREE , MEMORY_BASIC_INFORMATION , VirtualQuery ,
1156+ } ;
1157+
1158+ let mut mbi = MEMORY_BASIC_INFORMATION :: default ( ) ;
1159+ let result = unsafe {
1160+ VirtualQuery (
1161+ Some ( addr as * const c_void ) ,
1162+ & mut mbi,
1163+ std:: mem:: size_of :: < MEMORY_BASIC_INFORMATION > ( ) ,
1164+ )
1165+ } ;
1166+ assert_ne ! (
1167+ result, 0 ,
1168+ "VirtualQuery should succeed on mapped memory at address {:#x}" ,
1169+ addr as usize
1170+ ) ;
1171+ assert_ne ! (
1172+ mbi. State , MEM_FREE ,
1173+ "Memory should not be in MEM_FREE state before drop at address {:#x}" ,
1174+ addr as usize
1175+ ) ;
1176+ }
1177+
1178+ // Drop both shared memory instances, which should result
11631179 // in freeing the memory region
11641180 drop ( hshm1) ;
11651181 drop ( hshm2) ;
11661182 drop ( gshm) ;
11671183
1168- let maps_after_drop = proc_maps:: get_process_maps ( pid. try_into ( ) . unwrap ( ) ) . unwrap ( ) ;
1169- // now, ensure the address is not in the process's virtual memory
1170- assert ! (
1171- !maps_contain_addr( addr, & maps_after_drop) ,
1172- "shared memory address {:#x} was found in the process map, but shouldn't be" ,
1173- addr
1174- ) ;
1184+ // Verify memory is no longer accessible
1185+ #[ cfg( target_os = "linux" ) ]
1186+ {
1187+ // Try madvise on the unmapped memory - should fail with ENOMEM
1188+ let result =
1189+ unsafe { libc:: madvise ( addr as * mut libc:: c_void , size, libc:: MADV_NORMAL ) } ;
1190+ assert_eq ! (
1191+ result, -1 ,
1192+ "madvise should return -1 on unmapped memory at address {:#x}" ,
1193+ addr as usize
1194+ ) ;
1195+
1196+ let errno = std:: io:: Error :: last_os_error ( ) . raw_os_error ( ) . unwrap_or ( -1 ) ;
1197+ assert_eq ! (
1198+ errno,
1199+ libc:: ENOMEM ,
1200+ "Expected ENOMEM for unmapped memory, but got errno: {} at address {:#x}" ,
1201+ errno,
1202+ addr as usize
1203+ ) ;
1204+ }
1205+
1206+ #[ cfg( target_os = "windows" ) ]
1207+ {
1208+ use windows:: Win32 :: System :: Memory :: {
1209+ MEM_FREE , MEMORY_BASIC_INFORMATION , VirtualQuery ,
1210+ } ;
1211+
1212+ // Try VirtualQuery on the unmapped memory - should show MEM_FREE state
1213+ let mut mbi_after = MEMORY_BASIC_INFORMATION :: default ( ) ;
1214+ let result = unsafe {
1215+ VirtualQuery (
1216+ Some ( addr as * const c_void ) ,
1217+ & mut mbi_after,
1218+ std:: mem:: size_of :: < MEMORY_BASIC_INFORMATION > ( ) ,
1219+ )
1220+ } ;
1221+ assert_ne ! (
1222+ result, 0 ,
1223+ "VirtualQuery should succeed even on unmapped memory at address {:#x}" ,
1224+ addr as usize
1225+ ) ;
1226+ assert_eq ! (
1227+ mbi_after. State , MEM_FREE ,
1228+ "Memory should be in MEM_FREE state after drop at address {:#x}" ,
1229+ addr as usize
1230+ ) ;
1231+ }
11751232 }
11761233
11771234 #[ cfg( target_os = "linux" ) ]
0 commit comments