@@ -240,25 +240,43 @@ impl VirtAddr {
240240 }
241241
242242 // FIXME: Move this into the `Step` impl, once `Step` is stabilized.
243+ #[ cfg( feature = "step_trait" ) ]
244+ pub ( crate ) fn steps_between_impl ( start : & Self , end : & Self ) -> ( usize , Option < usize > ) {
245+ if let Some ( steps) = Self :: steps_between_u64 ( start, end) {
246+ let steps = usize:: try_from ( steps) . ok ( ) ;
247+ ( steps. unwrap_or ( usize:: MAX ) , steps)
248+ } else {
249+ ( 0 , None )
250+ }
251+ }
252+
253+ /// An implementation of steps_between that returns u64. Note that this
254+ /// function always returns the exact bound, so it doesn't need to return a
255+ /// lower and upper bound like steps_between does.
243256 #[ cfg( any( feature = "instructions" , feature = "step_trait" ) ) ]
244- pub ( crate ) fn steps_between_impl ( start : & Self , end : & Self ) -> Option < usize > {
257+ pub ( crate ) fn steps_between_u64 ( start : & Self , end : & Self ) -> Option < u64 > {
245258 let mut steps = end. 0 . checked_sub ( start. 0 ) ?;
246259
247260 // Mask away extra bits that appear while jumping the gap.
248261 steps &= 0xffff_ffff_ffff ;
249262
250- usize :: try_from ( steps) . ok ( )
263+ Some ( steps)
251264 }
252265
253266 // FIXME: Move this into the `Step` impl, once `Step` is stabilized.
254267 #[ inline]
255268 pub ( crate ) fn forward_checked_impl ( start : Self , count : usize ) -> Option < Self > {
256- let offset = u64:: try_from ( count) . ok ( ) ?;
257- if offset > ADDRESS_SPACE_SIZE {
269+ Self :: forward_checked_u64 ( start, u64:: try_from ( count) . ok ( ) ?)
270+ }
271+
272+ /// An implementation of forward_checked that takes u64 instead of usize.
273+ #[ inline]
274+ pub ( crate ) fn forward_checked_u64 ( start : Self , count : u64 ) -> Option < Self > {
275+ if count > ADDRESS_SPACE_SIZE {
258276 return None ;
259277 }
260278
261- let mut addr = start. 0 . checked_add ( offset ) ?;
279+ let mut addr = start. 0 . checked_add ( count ) ?;
262280
263281 match addr. get_bits ( 47 ..) {
264282 0x1 => {
@@ -274,6 +292,31 @@ impl VirtAddr {
274292
275293 Some ( unsafe { Self :: new_unsafe ( addr) } )
276294 }
295+
296+ /// An implementation of backward_checked that takes u64 instead of usize.
297+ #[ cfg( feature = "step_trait" ) ]
298+ #[ inline]
299+ pub ( crate ) fn backward_checked_u64 ( start : Self , count : u64 ) -> Option < Self > {
300+ if count > ADDRESS_SPACE_SIZE {
301+ return None ;
302+ }
303+
304+ let mut addr = start. 0 . checked_sub ( count) ?;
305+
306+ match addr. get_bits ( 47 ..) {
307+ 0x1fffe => {
308+ // Jump the gap by sign extending the 47th bit.
309+ addr. set_bits ( 47 .., 0 ) ;
310+ }
311+ 0x1fffd => {
312+ // Address underflow
313+ return None ;
314+ }
315+ _ => { }
316+ }
317+
318+ Some ( unsafe { Self :: new_unsafe ( addr) } )
319+ }
277320}
278321
279322impl fmt:: Debug for VirtAddr {
@@ -360,7 +403,7 @@ impl Sub<VirtAddr> for VirtAddr {
360403#[ cfg( feature = "step_trait" ) ]
361404impl Step for VirtAddr {
362405 #[ inline]
363- fn steps_between ( start : & Self , end : & Self ) -> Option < usize > {
406+ fn steps_between ( start : & Self , end : & Self ) -> ( usize , Option < usize > ) {
364407 Self :: steps_between_impl ( start, end)
365408 }
366409
@@ -371,26 +414,7 @@ impl Step for VirtAddr {
371414
372415 #[ inline]
373416 fn backward_checked ( start : Self , count : usize ) -> Option < Self > {
374- let offset = u64:: try_from ( count) . ok ( ) ?;
375- if offset > ADDRESS_SPACE_SIZE {
376- return None ;
377- }
378-
379- let mut addr = start. 0 . checked_sub ( offset) ?;
380-
381- match addr. get_bits ( 47 ..) {
382- 0x1fffe => {
383- // Jump the gap by sign extending the 47th bit.
384- addr. set_bits ( 47 .., 0 ) ;
385- }
386- 0x1fffd => {
387- // Address underflow
388- return None ;
389- }
390- _ => { }
391- }
392-
393- Some ( unsafe { Self :: new_unsafe ( addr) } )
417+ Self :: backward_checked_u64 ( start, u64:: try_from ( count) . ok ( ) ?)
394418 }
395419}
396420
@@ -664,22 +688,27 @@ mod tests {
664688 Step :: forward_checked( VirtAddr ( 0xffff_ffff_ffff_ffff ) , 1 ) ,
665689 None
666690 ) ;
691+ #[ cfg( target_pointer_width = "64" ) ]
667692 assert_eq ! (
668693 Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x1234_5678_9abd ) ,
669694 VirtAddr ( 0xffff_9234_5678_9abc )
670695 ) ;
696+ #[ cfg( target_pointer_width = "64" ) ]
671697 assert_eq ! (
672698 Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0000 ) ,
673699 VirtAddr ( 0xffff_ffff_ffff_ffff )
674700 ) ;
701+ #[ cfg( target_pointer_width = "64" ) ]
675702 assert_eq ! (
676703 Step :: forward( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_00ff ) ,
677704 VirtAddr ( 0xffff_ffff_ffff_ffff )
678705 ) ;
706+ #[ cfg( target_pointer_width = "64" ) ]
679707 assert_eq ! (
680708 Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_0100 ) ,
681709 None
682710 ) ;
711+ #[ cfg( target_pointer_width = "64" ) ]
683712 assert_eq ! (
684713 Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0001 ) ,
685714 None
@@ -700,18 +729,22 @@ mod tests {
700729 Step :: backward( VirtAddr ( 0xffff_8000_0000_0001 ) , 1 ) ,
701730 VirtAddr ( 0xffff_8000_0000_0000 )
702731 ) ;
732+ #[ cfg( target_pointer_width = "64" ) ]
703733 assert_eq ! (
704734 Step :: backward( VirtAddr ( 0xffff_9234_5678_9abc ) , 0x1234_5678_9abd ) ,
705735 VirtAddr ( 0x7fff_ffff_ffff )
706736 ) ;
737+ #[ cfg( target_pointer_width = "64" ) ]
707738 assert_eq ! (
708739 Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0000 ) ,
709740 VirtAddr ( 0 )
710741 ) ;
742+ #[ cfg( target_pointer_width = "64" ) ]
711743 assert_eq ! (
712744 Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x7fff_ffff_ff01 ) ,
713745 VirtAddr ( 0xff )
714746 ) ;
747+ #[ cfg( target_pointer_width = "64" ) ]
715748 assert_eq ! (
716749 Step :: backward_checked( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0001 ) ,
717750 None
@@ -721,43 +754,64 @@ mod tests {
721754 #[ test]
722755 #[ cfg( feature = "step_trait" ) ]
723756 fn virtaddr_steps_between ( ) {
724- assert_eq ! ( Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 0 ) ) , Some ( 0 ) ) ;
725- assert_eq ! ( Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 1 ) ) , Some ( 1 ) ) ;
726- assert_eq ! ( Step :: steps_between( & VirtAddr ( 1 ) , & VirtAddr ( 0 ) ) , None ) ;
757+ assert_eq ! (
758+ Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 0 ) ) ,
759+ ( 0 , Some ( 0 ) )
760+ ) ;
761+ assert_eq ! (
762+ Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 1 ) ) ,
763+ ( 1 , Some ( 1 ) )
764+ ) ;
765+ assert_eq ! ( Step :: steps_between( & VirtAddr ( 1 ) , & VirtAddr ( 0 ) ) , ( 0 , None ) ) ;
727766 assert_eq ! (
728767 Step :: steps_between(
729768 & VirtAddr ( 0x7fff_ffff_ffff ) ,
730769 & VirtAddr ( 0xffff_8000_0000_0000 )
731770 ) ,
732- Some ( 1 )
771+ ( 1 , Some ( 1 ) )
733772 ) ;
734773 assert_eq ! (
735774 Step :: steps_between(
736775 & VirtAddr ( 0xffff_8000_0000_0000 ) ,
737776 & VirtAddr ( 0x7fff_ffff_ffff )
738777 ) ,
739- None
778+ ( 0 , None )
740779 ) ;
741780 assert_eq ! (
742781 Step :: steps_between(
743782 & VirtAddr ( 0xffff_8000_0000_0000 ) ,
744783 & VirtAddr ( 0xffff_8000_0000_0000 )
745784 ) ,
746- Some ( 0 )
785+ ( 0 , Some ( 0 ) )
747786 ) ;
748787 assert_eq ! (
749788 Step :: steps_between(
750789 & VirtAddr ( 0xffff_8000_0000_0000 ) ,
751790 & VirtAddr ( 0xffff_8000_0000_0001 )
752791 ) ,
753- Some ( 1 )
792+ ( 1 , Some ( 1 ) )
754793 ) ;
755794 assert_eq ! (
756795 Step :: steps_between(
757796 & VirtAddr ( 0xffff_8000_0000_0001 ) ,
758797 & VirtAddr ( 0xffff_8000_0000_0000 )
759798 ) ,
760- None
799+ ( 0 , None )
800+ ) ;
801+ // Make sure that we handle `steps > u32::MAX` correctly on 32-bit
802+ // targets. On 64-bit targets, `0x1_0000_0000` fits into `usize`, so we
803+ // can return exact lower and upper bounds. On 32-bit targets,
804+ // `0x1_0000_0000` doesn't fit into `usize`, so we only return an lower
805+ // bound of `usize::MAX` and don't return an upper bound.
806+ #[ cfg( target_pointer_width = "64" ) ]
807+ assert_eq ! (
808+ Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 0x1_0000_0000 ) ) ,
809+ ( 0x1_0000_0000 , Some ( 0x1_0000_0000 ) )
810+ ) ;
811+ #[ cfg( not( target_pointer_width = "64" ) ) ]
812+ assert_eq ! (
813+ Step :: steps_between( & VirtAddr ( 0 ) , & VirtAddr ( 0x1_0000_0000 ) ) ,
814+ ( usize :: MAX , None )
761815 ) ;
762816 }
763817
@@ -809,10 +863,14 @@ mod tests {
809863 }
810864
811865 #[ test]
866+ #[ cfg( target_pointer_width = "64" ) ]
812867 fn test_from_ptr_array ( ) {
813868 let slice = & [ 1 , 2 , 3 , 4 , 5 ] ;
814869 // Make sure that from_ptr(slice) is the address of the first element
815- assert_eq ! ( VirtAddr :: from_ptr( slice) , VirtAddr :: from_ptr( & slice[ 0 ] ) ) ;
870+ assert_eq ! (
871+ VirtAddr :: from_ptr( slice. as_slice( ) ) ,
872+ VirtAddr :: from_ptr( & slice[ 0 ] )
873+ ) ;
816874 }
817875}
818876
@@ -951,7 +1009,7 @@ mod proofs {
9511009 } ;
9521010
9531011 // ...then `steps_between` succeeds as well.
954- assert ! ( Step :: steps_between( & start, & end) == Some ( count) ) ;
1012+ assert ! ( Step :: steps_between( & start, & end) == ( count , Some ( count) ) ) ;
9551013 }
9561014
9571015 // This harness proves that for all inputs for which `steps_between`
@@ -968,7 +1026,7 @@ mod proofs {
9681026 } ;
9691027
9701028 // If `steps_between` succeeds...
971- let Some ( count) = Step :: steps_between ( & start, & end) else {
1029+ let Some ( count) = Step :: steps_between ( & start, & end) . 1 else {
9721030 return ;
9731031 } ;
9741032
0 commit comments