@@ -240,25 +240,43 @@ impl VirtAddr {
240
240
}
241
241
242
242
// 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.
243
256
#[ 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 > {
245
258
let mut steps = end. 0 . checked_sub ( start. 0 ) ?;
246
259
247
260
// Mask away extra bits that appear while jumping the gap.
248
261
steps &= 0xffff_ffff_ffff ;
249
262
250
- usize :: try_from ( steps) . ok ( )
263
+ Some ( steps)
251
264
}
252
265
253
266
// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
254
267
#[ inline]
255
268
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 {
258
276
return None ;
259
277
}
260
278
261
- let mut addr = start. 0 . checked_add ( offset ) ?;
279
+ let mut addr = start. 0 . checked_add ( count ) ?;
262
280
263
281
match addr. get_bits ( 47 ..) {
264
282
0x1 => {
@@ -274,6 +292,31 @@ impl VirtAddr {
274
292
275
293
Some ( unsafe { Self :: new_unsafe ( addr) } )
276
294
}
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
+ }
277
320
}
278
321
279
322
impl fmt:: Debug for VirtAddr {
@@ -360,7 +403,7 @@ impl Sub<VirtAddr> for VirtAddr {
360
403
#[ cfg( feature = "step_trait" ) ]
361
404
impl Step for VirtAddr {
362
405
#[ inline]
363
- fn steps_between ( start : & Self , end : & Self ) -> Option < usize > {
406
+ fn steps_between ( start : & Self , end : & Self ) -> ( usize , Option < usize > ) {
364
407
Self :: steps_between_impl ( start, end)
365
408
}
366
409
@@ -371,26 +414,7 @@ impl Step for VirtAddr {
371
414
372
415
#[ inline]
373
416
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 ( ) ?)
394
418
}
395
419
}
396
420
@@ -664,22 +688,27 @@ mod tests {
664
688
Step :: forward_checked( VirtAddr ( 0xffff_ffff_ffff_ffff ) , 1 ) ,
665
689
None
666
690
) ;
691
+ #[ cfg( target_pointer_width = "64" ) ]
667
692
assert_eq ! (
668
693
Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x1234_5678_9abd ) ,
669
694
VirtAddr ( 0xffff_9234_5678_9abc )
670
695
) ;
696
+ #[ cfg( target_pointer_width = "64" ) ]
671
697
assert_eq ! (
672
698
Step :: forward( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0000 ) ,
673
699
VirtAddr ( 0xffff_ffff_ffff_ffff )
674
700
) ;
701
+ #[ cfg( target_pointer_width = "64" ) ]
675
702
assert_eq ! (
676
703
Step :: forward( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_00ff ) ,
677
704
VirtAddr ( 0xffff_ffff_ffff_ffff )
678
705
) ;
706
+ #[ cfg( target_pointer_width = "64" ) ]
679
707
assert_eq ! (
680
708
Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ff00 ) , 0x8000_0000_0100 ) ,
681
709
None
682
710
) ;
711
+ #[ cfg( target_pointer_width = "64" ) ]
683
712
assert_eq ! (
684
713
Step :: forward_checked( VirtAddr ( 0x7fff_ffff_ffff ) , 0x8000_0000_0001 ) ,
685
714
None
@@ -700,18 +729,22 @@ mod tests {
700
729
Step :: backward( VirtAddr ( 0xffff_8000_0000_0001 ) , 1 ) ,
701
730
VirtAddr ( 0xffff_8000_0000_0000 )
702
731
) ;
732
+ #[ cfg( target_pointer_width = "64" ) ]
703
733
assert_eq ! (
704
734
Step :: backward( VirtAddr ( 0xffff_9234_5678_9abc ) , 0x1234_5678_9abd ) ,
705
735
VirtAddr ( 0x7fff_ffff_ffff )
706
736
) ;
737
+ #[ cfg( target_pointer_width = "64" ) ]
707
738
assert_eq ! (
708
739
Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0000 ) ,
709
740
VirtAddr ( 0 )
710
741
) ;
742
+ #[ cfg( target_pointer_width = "64" ) ]
711
743
assert_eq ! (
712
744
Step :: backward( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x7fff_ffff_ff01 ) ,
713
745
VirtAddr ( 0xff )
714
746
) ;
747
+ #[ cfg( target_pointer_width = "64" ) ]
715
748
assert_eq ! (
716
749
Step :: backward_checked( VirtAddr ( 0xffff_8000_0000_0000 ) , 0x8000_0000_0001 ) ,
717
750
None
@@ -721,43 +754,64 @@ mod tests {
721
754
#[ test]
722
755
#[ cfg( feature = "step_trait" ) ]
723
756
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 ) ) ;
727
766
assert_eq ! (
728
767
Step :: steps_between(
729
768
& VirtAddr ( 0x7fff_ffff_ffff ) ,
730
769
& VirtAddr ( 0xffff_8000_0000_0000 )
731
770
) ,
732
- Some ( 1 )
771
+ ( 1 , Some ( 1 ) )
733
772
) ;
734
773
assert_eq ! (
735
774
Step :: steps_between(
736
775
& VirtAddr ( 0xffff_8000_0000_0000 ) ,
737
776
& VirtAddr ( 0x7fff_ffff_ffff )
738
777
) ,
739
- None
778
+ ( 0 , None )
740
779
) ;
741
780
assert_eq ! (
742
781
Step :: steps_between(
743
782
& VirtAddr ( 0xffff_8000_0000_0000 ) ,
744
783
& VirtAddr ( 0xffff_8000_0000_0000 )
745
784
) ,
746
- Some ( 0 )
785
+ ( 0 , Some ( 0 ) )
747
786
) ;
748
787
assert_eq ! (
749
788
Step :: steps_between(
750
789
& VirtAddr ( 0xffff_8000_0000_0000 ) ,
751
790
& VirtAddr ( 0xffff_8000_0000_0001 )
752
791
) ,
753
- Some ( 1 )
792
+ ( 1 , Some ( 1 ) )
754
793
) ;
755
794
assert_eq ! (
756
795
Step :: steps_between(
757
796
& VirtAddr ( 0xffff_8000_0000_0001 ) ,
758
797
& VirtAddr ( 0xffff_8000_0000_0000 )
759
798
) ,
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 )
761
815
) ;
762
816
}
763
817
@@ -809,10 +863,14 @@ mod tests {
809
863
}
810
864
811
865
#[ test]
866
+ #[ cfg( target_pointer_width = "64" ) ]
812
867
fn test_from_ptr_array ( ) {
813
868
let slice = & [ 1 , 2 , 3 , 4 , 5 ] ;
814
869
// 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
+ ) ;
816
874
}
817
875
}
818
876
@@ -951,7 +1009,7 @@ mod proofs {
951
1009
} ;
952
1010
953
1011
// ...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) ) ) ;
955
1013
}
956
1014
957
1015
// This harness proves that for all inputs for which `steps_between`
@@ -968,7 +1026,7 @@ mod proofs {
968
1026
} ;
969
1027
970
1028
// 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 {
972
1030
return ;
973
1031
} ;
974
1032
0 commit comments