Add precondition checks to ptr::offset, ptr::add, ptr::sub · qinheping/verify-rust-std@8293e74 (original) (raw)
`@@ -395,6 +395,36 @@ impl<T: ?Sized> *const T {
`
395
395
`where
`
396
396
`T: Sized,
`
397
397
`{
`
``
398
`+
#[inline]
`
``
399
`+
const fn runtime_offset_nowrap(this: *const (), count: isize, size: usize) -> bool {
`
``
400
`+
#[inline]
`
``
401
`+
fn runtime(this: *const (), count: isize, size: usize) -> bool {
`
``
402
`` +
// We know size <= isize::MAX
so the as
cast here is not lossy.
``
``
403
`+
let Some(byte_offset) = count.checked_mul(size as isize) else {
`
``
404
`+
return false;
`
``
405
`+
};
`
``
406
`+
let (_, overflow) = this.addr().overflowing_add_signed(byte_offset);
`
``
407
`+
!overflow
`
``
408
`+
}
`
``
409
+
``
410
`+
const fn comptime(_: *const (), _: isize, _: usize) -> bool {
`
``
411
`+
true
`
``
412
`+
}
`
``
413
+
``
414
`+
// We can use const_eval_select here because this is only for UB checks.
`
``
415
`+
intrinsics::const_eval_select((this, count, size), comptime, runtime)
`
``
416
`+
}
`
``
417
+
``
418
`+
ub_checks::assert_unsafe_precondition!(
`
``
419
`+
check_language_ub,
`
``
420
`+
"ptr::offset requires the address calculation to not overflow",
`
``
421
`+
(
`
``
422
`+
this: *const () = self as *const (),
`
``
423
`+
count: isize = count,
`
``
424
`+
size: usize = size_of::(),
`
``
425
`+
) => runtime_offset_nowrap(this, count, size)
`
``
426
`+
);
`
``
427
+
398
428
`` // SAFETY: the caller must uphold the safety contract for offset
.
``
399
429
`unsafe { intrinsics::offset(self, count) }
`
400
430
`}
`
`@@ -726,7 +756,6 @@ impl<T: ?Sized> *const T {
`
726
756
`true
`
727
757
`}
`
728
758
``
729
``
`-
#[allow(unused_unsafe)]
`
730
759
` intrinsics::const_eval_select((this, origin), comptime, runtime)
`
731
760
`}
`
732
761
``
`@@ -858,6 +887,34 @@ impl<T: ?Sized> *const T {
`
858
887
`where
`
859
888
`T: Sized,
`
860
889
`{
`
``
890
`+
#[inline]
`
``
891
`+
const fn runtime_add_nowrap(this: *const (), count: usize, size: usize) -> bool {
`
``
892
`+
#[inline]
`
``
893
`+
fn runtime(this: *const (), count: usize, size: usize) -> bool {
`
``
894
`+
let Some(byte_offset) = count.checked_mul(size) else {
`
``
895
`+
return false;
`
``
896
`+
};
`
``
897
`+
let (_, overflow) = this.addr().overflowing_add(byte_offset);
`
``
898
`+
byte_offset <= (isize::MAX as usize) && !overflow
`
``
899
`+
}
`
``
900
+
``
901
`+
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
`
``
902
`+
true
`
``
903
`+
}
`
``
904
+
``
905
`+
intrinsics::const_eval_select((this, count, size), comptime, runtime)
`
``
906
`+
}
`
``
907
+
``
908
`+
ub_checks::assert_unsafe_precondition!(
`
``
909
`+
check_language_ub,
`
``
910
`+
"ptr::add requires that the address calculation does not overflow",
`
``
911
`+
(
`
``
912
`+
this: *const () = self as *const (),
`
``
913
`+
count: usize = count,
`
``
914
`+
size: usize = size_of::(),
`
``
915
`+
) => runtime_add_nowrap(this, count, size)
`
``
916
`+
);
`
``
917
+
861
918
`` // SAFETY: the caller must uphold the safety contract for offset
.
``
862
919
`unsafe { intrinsics::offset(self, count) }
`
863
920
`}
`
`@@ -936,14 +993,41 @@ impl<T: ?Sized> *const T {
`
936
993
`where
`
937
994
`T: Sized,
`
938
995
`{
`
``
996
`+
#[inline]
`
``
997
`+
const fn runtime_sub_nowrap(this: *const (), count: usize, size: usize) -> bool {
`
``
998
`+
#[inline]
`
``
999
`+
fn runtime(this: *const (), count: usize, size: usize) -> bool {
`
``
1000
`+
let Some(byte_offset) = count.checked_mul(size) else {
`
``
1001
`+
return false;
`
``
1002
`+
};
`
``
1003
`+
byte_offset <= (isize::MAX as usize) && this.addr() >= byte_offset
`
``
1004
`+
}
`
``
1005
+
``
1006
`+
const fn comptime(_: *const (), _: usize, _: usize) -> bool {
`
``
1007
`+
true
`
``
1008
`+
}
`
``
1009
+
``
1010
`+
intrinsics::const_eval_select((this, count, size), comptime, runtime)
`
``
1011
`+
}
`
``
1012
+
``
1013
`+
ub_checks::assert_unsafe_precondition!(
`
``
1014
`+
check_language_ub,
`
``
1015
`+
"ptr::sub requires that the address calculation does not overflow",
`
``
1016
`+
(
`
``
1017
`+
this: *const () = self as *const (),
`
``
1018
`+
count: usize = count,
`
``
1019
`+
size: usize = size_of::(),
`
``
1020
`+
) => runtime_sub_nowrap(this, count, size)
`
``
1021
`+
);
`
``
1022
+
939
1023
`if T::IS_ZST {
`
940
1024
`// Pointer arithmetic does nothing when the pointee is a ZST.
`
941
1025
`self
`
942
1026
`} else {
`
943
1027
`` // SAFETY: the caller must uphold the safety contract for offset
.
``
944
1028
`` // Because the pointee is not a ZST, that means that count
is
``
945
1029
`` // at most isize::MAX
, and thus the negation cannot overflow.
``
946
``
`-
unsafe { self.offset((count as isize).unchecked_neg()) }
`
``
1030
`+
unsafe { intrinsics::offset(self, intrinsics::unchecked_sub(0, count as isize)) }
`
947
1031
`}
`
948
1032
`}
`
949
1033
``