@@ -18,7 +18,7 @@ use cbmc::MachineModel;
1818use cbmc:: { btree_string_map, InternString , InternedString } ;
1919use num:: bigint:: BigInt ;
2020use rustc_abi:: FieldIdx ;
21- use rustc_index:: vec :: IndexVec ;
21+ use rustc_index:: IndexVec ;
2222use rustc_middle:: mir:: { AggregateKind , BinOp , CastKind , NullOp , Operand , Place , Rvalue , UnOp } ;
2323use rustc_middle:: ty:: adjustment:: PointerCast ;
2424use rustc_middle:: ty:: layout:: LayoutOf ;
@@ -294,6 +294,7 @@ impl<'tcx> GotocCtx<'tcx> {
294294
295295 fn codegen_rvalue_binary_op (
296296 & mut self ,
297+ ty : Ty < ' tcx > ,
297298 op : & BinOp ,
298299 e1 : & Operand < ' tcx > ,
299300 e2 : & Operand < ' tcx > ,
@@ -317,7 +318,32 @@ impl<'tcx> GotocCtx<'tcx> {
317318 BinOp :: Offset => {
318319 let ce1 = self . codegen_operand ( e1) ;
319320 let ce2 = self . codegen_operand ( e2) ;
320- ce1. plus ( ce2)
321+
322+ // Check that computing `offset` in bytes would not overflow
323+ let ( offset_bytes, bytes_overflow_check) = self . count_in_bytes (
324+ ce2. clone ( ) . cast_to ( Type :: ssize_t ( ) ) ,
325+ ty,
326+ Type :: ssize_t ( ) ,
327+ "offset" ,
328+ loc,
329+ ) ;
330+
331+ // Check that the computation would not overflow an `isize` which is UB:
332+ // https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
333+ // These checks may allow a wrapping-around behavior in CBMC:
334+ // https://github.com/model-checking/kani/issues/1150
335+ let overflow_res = ce1. clone ( ) . cast_to ( Type :: ssize_t ( ) ) . add_overflow ( offset_bytes) ;
336+ let overflow_check = self . codegen_assert_assume (
337+ overflow_res. overflowed . not ( ) ,
338+ PropertyClass :: ArithmeticOverflow ,
339+ "attempt to compute offset which would overflow" ,
340+ loc,
341+ ) ;
342+ let res = ce1. clone ( ) . plus ( ce2) ;
343+ Expr :: statement_expression (
344+ vec ! [ bytes_overflow_check, overflow_check, res. as_stmt( loc) ] ,
345+ ce1. typ ( ) . clone ( ) ,
346+ )
321347 }
322348 }
323349 }
@@ -548,7 +574,7 @@ impl<'tcx> GotocCtx<'tcx> {
548574 self . codegen_operand ( operand) . transmute_to ( goto_typ, & self . symbol_table )
549575 }
550576 Rvalue :: BinaryOp ( op, box ( ref e1, ref e2) ) => {
551- self . codegen_rvalue_binary_op ( op, e1, e2, loc)
577+ self . codegen_rvalue_binary_op ( res_ty , op, e1, e2, loc)
552578 }
553579 Rvalue :: CheckedBinaryOp ( op, box ( ref e1, ref e2) ) => {
554580 self . codegen_rvalue_checked_binary_op ( op, e1, e2, res_ty)
@@ -560,6 +586,10 @@ impl<'tcx> GotocCtx<'tcx> {
560586 NullOp :: SizeOf => Expr :: int_constant ( layout. size . bytes_usize ( ) , Type :: size_t ( ) )
561587 . with_size_of_annotation ( self . codegen_ty ( t) ) ,
562588 NullOp :: AlignOf => Expr :: int_constant ( layout. align . abi . bytes ( ) , Type :: size_t ( ) ) ,
589+ NullOp :: OffsetOf ( fields) => Expr :: int_constant (
590+ layout. offset_of_subfield ( self , fields. iter ( ) . map ( |f| f. index ( ) ) ) . bytes ( ) ,
591+ Type :: size_t ( ) ,
592+ ) ,
563593 }
564594 }
565595 Rvalue :: ShallowInitBox ( ref operand, content_ty) => {
0 commit comments