@@ -528,7 +528,7 @@ impl<'tcx> GotocCtx<'tcx> {
528
528
"pref_align_of" => codegen_intrinsic_const ! ( ) ,
529
529
"ptr_guaranteed_eq" => codegen_ptr_guaranteed_cmp ! ( eq) ,
530
530
"ptr_guaranteed_ne" => codegen_ptr_guaranteed_cmp ! ( neq) ,
531
- "ptr_offset_from" => self . codegen_ptr_offset_from ( instance , fargs, p, loc) ,
531
+ "ptr_offset_from" => self . codegen_ptr_offset_from ( fargs, p, loc) ,
532
532
"raw_eq" => self . codegen_intrinsic_raw_eq ( instance, fargs, p, loc) ,
533
533
"rintf32" => codegen_unimplemented_intrinsic ! (
534
534
"https://github.com/model-checking/kani/issues/1025"
@@ -637,7 +637,7 @@ impl<'tcx> GotocCtx<'tcx> {
637
637
"wrapping_sub" => codegen_wrapping_op ! ( sub) ,
638
638
"write_bytes" => {
639
639
assert ! ( self . place_ty( p) . is_unit( ) ) ;
640
- self . codegen_write_bytes ( instance, intrinsic , fargs, loc)
640
+ self . codegen_write_bytes ( instance, fargs, loc)
641
641
}
642
642
// Unimplemented
643
643
_ => codegen_unimplemented_intrinsic ! (
@@ -887,26 +887,22 @@ impl<'tcx> GotocCtx<'tcx> {
887
887
let src_ptr = fargs. remove ( 0 ) ;
888
888
let offset = fargs. remove ( 0 ) ;
889
889
890
- // Check that computing `bytes` would not overflow
890
+ // Check that computing `offset` in bytes would not overflow
891
891
let ty = self . monomorphize ( instance. substs . type_at ( 0 ) ) ;
892
- let layout = self . layout_of ( ty) ;
893
- let size = Expr :: int_constant ( layout. size . bytes ( ) , Type :: ssize_t ( ) ) ;
894
- let bytes = offset. clone ( ) . mul_overflow ( size) ;
895
- let bytes_overflow_check = self . codegen_assert (
896
- bytes. overflowed . not ( ) ,
897
- PropertyClass :: ArithmeticOverflow ,
898
- "attempt to compute offset in bytes which would overflow" ,
899
- loc,
900
- ) ;
892
+ let ( offset_bytes, bytes_overflow_check) =
893
+ self . count_in_bytes ( offset. clone ( ) , ty, Type :: ssize_t ( ) , "offset" , loc) ;
901
894
902
895
// Check that the computation would not overflow an `isize`
903
- let dst_ptr_of = src_ptr. clone ( ) . cast_to ( Type :: ssize_t ( ) ) . add_overflow ( bytes. result ) ;
896
+ // These checks may allow a wrapping-around behavior in CBMC:
897
+ // https://github.com/model-checking/kani/issues/1150
898
+ let dst_ptr_of = src_ptr. clone ( ) . cast_to ( Type :: ssize_t ( ) ) . add_overflow ( offset_bytes) ;
904
899
let overflow_check = self . codegen_assert (
905
900
dst_ptr_of. overflowed . not ( ) ,
906
901
PropertyClass :: ArithmeticOverflow ,
907
902
"attempt to compute offset which would overflow" ,
908
903
loc,
909
904
) ;
905
+
910
906
// Re-compute `dst_ptr` with standard addition to avoid conversion
911
907
let dst_ptr = src_ptr. plus ( offset) ;
912
908
let expr_place = self . codegen_expr_to_place ( p, dst_ptr) ;
@@ -917,7 +913,6 @@ impl<'tcx> GotocCtx<'tcx> {
917
913
/// https://doc.rust-lang.org/std/intrinsics/fn.ptr_offset_from.html
918
914
fn codegen_ptr_offset_from (
919
915
& mut self ,
920
- instance : Instance < ' tcx > ,
921
916
mut fargs : Vec < Expr > ,
922
917
p : & Place < ' tcx > ,
923
918
loc : Location ,
@@ -928,17 +923,15 @@ impl<'tcx> GotocCtx<'tcx> {
928
923
// Compute the offset with standard substraction using `isize`
929
924
let cast_dst_ptr = dst_ptr. clone ( ) . cast_to ( Type :: ssize_t ( ) ) ;
930
925
let cast_src_ptr = src_ptr. clone ( ) . cast_to ( Type :: ssize_t ( ) ) ;
931
- let offset = cast_dst_ptr. sub ( cast_src_ptr) ;
926
+ let offset = cast_dst_ptr. sub_overflow ( cast_src_ptr) ;
932
927
933
- // Check that computing `offset_bytes` would not overflow an `isize`
934
- let ty = self . monomorphize ( instance. substs . type_at ( 0 ) ) ;
935
- let layout = self . layout_of ( ty) ;
936
- let size = Expr :: int_constant ( layout. size . bytes ( ) , Type :: ssize_t ( ) ) ;
937
- let offset_bytes = offset. clone ( ) . mul_overflow ( size) ;
928
+ // Check that computing `offset` in bytes would not overflow an `isize`
929
+ // These checks may allow a wrapping-around behavior in CBMC:
930
+ // https://github.com/model-checking/kani/issues/1150
938
931
let overflow_check = self . codegen_assert (
939
- offset_bytes . overflowed . not ( ) ,
932
+ offset . overflowed . not ( ) ,
940
933
PropertyClass :: ArithmeticOverflow ,
941
- "attempt to compute offset in bytes which would overflow" ,
934
+ "attempt to compute offset in bytes which would overflow an `isize` " ,
942
935
loc,
943
936
) ;
944
937
@@ -1218,7 +1211,6 @@ impl<'tcx> GotocCtx<'tcx> {
1218
1211
fn codegen_write_bytes (
1219
1212
& mut self ,
1220
1213
instance : Instance < ' tcx > ,
1221
- intrinsic : & str ,
1222
1214
mut fargs : Vec < Expr > ,
1223
1215
loc : Location ,
1224
1216
) -> Stmt {
@@ -1236,18 +1228,41 @@ impl<'tcx> GotocCtx<'tcx> {
1236
1228
loc,
1237
1229
) ;
1238
1230
1239
- // Check that computing `bytes` would not overflow
1231
+ // Check that computing `count` in bytes would not overflow
1232
+ let ( count_bytes, overflow_check) =
1233
+ self . count_in_bytes ( count, ty, Type :: size_t ( ) , "write_bytes" , loc) ;
1234
+
1235
+ let memset_call = BuiltinFn :: Memset . call ( vec ! [ dst, val, count_bytes] , loc) ;
1236
+ Stmt :: block ( vec ! [ align_check, overflow_check, memset_call. as_stmt( loc) ] , loc)
1237
+ }
1238
+
1239
+ /// Computes (multiplies) the equivalent of a memory-related number (e.g., an offset) in bytes.
1240
+ /// Because this operation may result in an arithmetic overflow, it includes an overflow check.
1241
+ /// Returns a tuple with:
1242
+ /// * The result expression of the computation.
1243
+ /// * An assertion statement to ensure the operation has not overflowed.
1244
+ fn count_in_bytes (
1245
+ & self ,
1246
+ count : Expr ,
1247
+ ty : Ty < ' tcx > ,
1248
+ res_ty : Type ,
1249
+ intrinsic : & str ,
1250
+ loc : Location ,
1251
+ ) -> ( Expr , Stmt ) {
1252
+ assert ! ( res_ty. is_integer( ) ) ;
1240
1253
let layout = self . layout_of ( ty) ;
1241
- let size = Expr :: int_constant ( layout. size . bytes ( ) , Type :: size_t ( ) ) ;
1242
- let bytes = count. mul_overflow ( size) ;
1243
- let overflow_check = self . codegen_assert (
1244
- bytes. overflowed . not ( ) ,
1254
+ let size_of_elem = Expr :: int_constant ( layout. size . bytes ( ) , res_ty) ;
1255
+ let size_of_count_elems = count. mul_overflow ( size_of_elem) ;
1256
+ let message = format ! (
1257
+ "{}: attempt to compute number in bytes which would overflow" ,
1258
+ intrinsic. to_string( )
1259
+ ) ;
1260
+ let assert_stmt = self . codegen_assert (
1261
+ size_of_count_elems. overflowed . not ( ) ,
1245
1262
PropertyClass :: ArithmeticOverflow ,
1246
- format ! ( "{}: attempt to compute `bytes` which would overflow" , intrinsic ) . as_str ( ) ,
1263
+ message . as_str ( ) ,
1247
1264
loc,
1248
1265
) ;
1249
-
1250
- let memset_call = BuiltinFn :: Memset . call ( vec ! [ dst, val, bytes. result] , loc) ;
1251
- Stmt :: block ( vec ! [ align_check, overflow_check, memset_call. as_stmt( loc) ] , loc)
1266
+ ( size_of_count_elems. result , assert_stmt)
1252
1267
}
1253
1268
}
0 commit comments