Skip to content

Commit d0b74ca

Browse files
authored
Update the rust toolchain to nightly-2022-05-03 (#1181)
* Update rust toolchain to nightly-2022-05-03 This compiles but regression is failing due to unimplemented statement. * Handle change to Box<T> structure Box<T> now users NonNull<T> instead of raw pointer. * Handle new statement kind Deinit We codegen an assignment to non-det value per documentation. See more information here: - rust-lang/rust#95125 * Fix discriminant computation After the merge, the previous wrapping sub logic was triggering a panic due to u128 -> i64 conversion. There were also other overflow issues when trying to convert the `niche_value` to unsigned. For now, I'm disabling the coversion check which I believe is too strict. We should consider implementing a more flexible check later that can be controlled by the user without affecting the internal compiler codegen. * Address PR comments: - Improve comments. - Remove wrong cast to i64. - Fix statement location. - Create util function to create unsigned type.
1 parent 0805270 commit d0b74ca

File tree

16 files changed

+258
-202
lines changed

16 files changed

+258
-202
lines changed

cprover_bindings/src/goto_program/typ.rs

+13
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,19 @@ impl Type {
973973
Pointer { typ: Box::new(self) }
974974
}
975975

976+
/// Convert type to its unsigned counterpart if possible.
977+
/// For types that are already unsigned, this will return self.
978+
/// Note: This will expand any typedef.
979+
pub fn to_unsigned(&self) -> Option<Self> {
980+
let concrete = self.unwrap_typedef();
981+
match concrete {
982+
CInteger(CIntType::SSizeT) => Some(CInteger(CIntType::SizeT)),
983+
Signedbv { ref width } => Some(Unsignedbv { width: *width }),
984+
Unsignedbv { .. } => Some(self.clone()),
985+
_ => None,
986+
}
987+
}
988+
976989
pub fn signed_int<T>(w: T) -> Self
977990
where
978991
T: TryInto<u64>,

kani-compiler/src/codegen_cprover_gotoc/codegen/rvalue.rs

+27-32
Original file line numberDiff line numberDiff line change
@@ -472,19 +472,27 @@ impl<'tcx> GotocCtx<'tcx> {
472472
FieldsShape::Arbitrary { offsets, .. } => offsets[0].bytes_usize(),
473473
_ => unreachable!("niche encoding must have arbitrary fields"),
474474
};
475-
let discr_ty = self.codegen_enum_discr_typ(ty);
476-
let discr_ty = self.codegen_ty(discr_ty);
477-
let niche_val = self.codegen_get_niche(e, offset, discr_ty.clone());
478-
let relative_discr = if *niche_start == 0 {
479-
niche_val
480-
} else {
481-
wrapping_sub(&niche_val, *niche_start)
482-
};
475+
476+
// Compute relative discriminant value (`niche_val - niche_start`).
477+
//
478+
// "We remap `niche_start..=niche_start + n` (which may wrap around) to
479+
// (non-wrap-around) `0..=n`, to be able to check whether the discriminant
480+
// corresponds to a niche variant with one comparison."
481+
// https://github.com/rust-lang/rust/blob/fee75fbe11b1fad5d93c723234178b2a329a3c03/compiler/rustc_codegen_ssa/src/mir/place.rs#L247
482+
//
483+
// Note: niche_variants can only represent values that fit in a u32.
484+
let discr_mir_ty = self.codegen_enum_discr_typ(ty);
485+
let discr_type = self.codegen_ty(discr_mir_ty);
486+
let niche_val = self.codegen_get_niche(e, offset, discr_type.clone());
487+
let relative_discr =
488+
wrapping_sub(&niche_val, u64::try_from(*niche_start).unwrap());
483489
let relative_max =
484490
niche_variants.end().as_u32() - niche_variants.start().as_u32();
485-
let is_niche = if tag.value == Primitive::Pointer {
486-
discr_ty.null().eq(relative_discr.clone())
491+
let is_niche = if tag.primitive() == Primitive::Pointer {
492+
tracing::trace!(?tag, "Primitive::Pointer");
493+
discr_type.null().eq(relative_discr.clone())
487494
} else {
495+
tracing::trace!(?tag, "Not Primitive::Pointer");
488496
relative_discr
489497
.clone()
490498
.le(Expr::int_constant(relative_max, relative_discr.typ().clone()))
@@ -1260,26 +1268,13 @@ impl<'tcx> GotocCtx<'tcx> {
12601268
/// Perform a wrapping subtraction of an Expr with a constant "expr - constant"
12611269
/// where "-" is wrapping subtraction, i.e., the result should be interpreted as
12621270
/// an unsigned value (2's complement).
1263-
fn wrapping_sub(expr: &Expr, constant: u128) -> Expr {
1264-
// While the wrapping subtraction can be done through a regular subtraction
1265-
// and then casting the result to an unsigned, doing so may result in CBMC
1266-
// flagging the operation with a signed to unsigned overflow failure (see
1267-
// https://github.com/model-checking/kani/issues/356).
1268-
// To avoid those overflow failures, the wrapping subtraction operation is
1269-
// computed as:
1270-
// if expr >= constant {
1271-
// // result is positive, so overflow may not occur
1272-
// expr - constant
1273-
// } else {
1274-
// // compute the 2's complement to avoid overflow
1275-
// expr - constant + 2^32
1276-
// }
1277-
let s64 = Type::signed_int(64);
1278-
let expr = expr.clone().cast_to(s64.clone());
1279-
let twos_complement: i64 = u32::MAX as i64 + 1 - i64::try_from(constant).unwrap();
1280-
let constant = Expr::int_constant(constant, s64.clone());
1281-
expr.clone().ge(constant.clone()).ternary(
1282-
expr.clone().sub(constant),
1283-
expr.plus(Expr::int_constant(twos_complement, s64.clone())),
1284-
)
1271+
fn wrapping_sub(expr: &Expr, constant: u64) -> Expr {
1272+
if constant == 0 {
1273+
// No need to subtract.
1274+
expr.clone()
1275+
} else {
1276+
let unsigned = expr.typ().to_unsigned().unwrap();
1277+
let constant = Expr::int_constant(constant, unsigned.clone());
1278+
expr.clone().cast_to(unsigned).sub(constant)
1279+
}
12851280
}

kani-compiler/src/codegen_cprover_gotoc/codegen/statement.rs

+38-24
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ impl<'tcx> GotocCtx<'tcx> {
603603
pub fn codegen_statement(&mut self, stmt: &Statement<'tcx>) -> Stmt {
604604
let _trace_span = info_span!("CodegenStatement", statement = ?stmt).entered();
605605
debug!("handling statement {:?}", stmt);
606+
let location = self.codegen_span(&stmt.source_info.span);
606607
match &stmt.kind {
607608
StatementKind::Assign(box (l, r)) => {
608609
let lty = self.place_ty(l);
@@ -617,15 +618,32 @@ impl<'tcx> GotocCtx<'tcx> {
617618
// where the reference is implicit.
618619
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(l))
619620
.goto_expr
620-
.assign(self.codegen_rvalue(r).address_of(), Location::none())
621+
.assign(self.codegen_rvalue(r).address_of(), location)
621622
} else if rty.is_bool() {
622623
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(l))
623624
.goto_expr
624-
.assign(self.codegen_rvalue(r).cast_to(Type::c_bool()), Location::none())
625+
.assign(self.codegen_rvalue(r).cast_to(Type::c_bool()), location)
625626
} else {
626627
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(l))
627628
.goto_expr
628-
.assign(self.codegen_rvalue(r), Location::none())
629+
.assign(self.codegen_rvalue(r), location)
630+
}
631+
}
632+
StatementKind::Deinit(place) => {
633+
// From rustc doc: "This writes `uninit` bytes to the entire place."
634+
// Thus, we assign nondet() value to the entire place.
635+
let dst_mir_ty = self.place_ty(place);
636+
let dst_type = self.codegen_ty(dst_mir_ty);
637+
let layout = self.layout_of(dst_mir_ty);
638+
if layout.is_zst() || dst_type.sizeof_in_bits(&self.symbol_table) == 0 {
639+
// We ignore assignment for all zero size types
640+
// Ignore generators too for now:
641+
// https://github.com/model-checking/kani/issues/416
642+
Stmt::skip(location)
643+
} else {
644+
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(place))
645+
.goto_expr
646+
.assign(dst_type.nondet(), location)
629647
}
630648
}
631649
StatementKind::SetDiscriminant { place, variant_index } => {
@@ -638,16 +656,16 @@ impl<'tcx> GotocCtx<'tcx> {
638656
.codegen_unimplemented(
639657
"ty::Generator",
640658
Type::code(vec![], Type::empty()),
641-
Location::none(),
659+
location.clone(),
642660
"https://github.com/model-checking/kani/issues/416",
643661
)
644-
.as_stmt(Location::none());
662+
.as_stmt(location);
645663
}
646664
_ => unreachable!(),
647665
};
648666
let layout = self.layout_of(pt);
649667
match &layout.variants {
650-
Variants::Single { .. } => Stmt::skip(Location::none()),
668+
Variants::Single { .. } => Stmt::skip(location),
651669
Variants::Multiple { tag, tag_encoding, .. } => match tag_encoding {
652670
TagEncoding::Direct => {
653671
let discr = def.discriminant_for_variant(self.tcx, *variant_index);
@@ -671,7 +689,7 @@ impl<'tcx> GotocCtx<'tcx> {
671689
)
672690
.goto_expr
673691
.member("case", &self.symbol_table)
674-
.assign(discr, Location::none())
692+
.assign(discr, location)
675693
}
676694
TagEncoding::Niche { dataful_variant, niche_variants, niche_start } => {
677695
if dataful_variant != variant_index {
@@ -686,27 +704,28 @@ impl<'tcx> GotocCtx<'tcx> {
686704
let niche_value =
687705
variant_index.as_u32() - niche_variants.start().as_u32();
688706
let niche_value = (niche_value as u128).wrapping_add(*niche_start);
689-
let value = if niche_value == 0 && tag.value == Primitive::Pointer {
690-
discr_ty.null()
691-
} else {
692-
Expr::int_constant(niche_value, discr_ty.clone())
693-
};
707+
let value =
708+
if niche_value == 0 && tag.primitive() == Primitive::Pointer {
709+
discr_ty.null()
710+
} else {
711+
Expr::int_constant(niche_value, discr_ty.clone())
712+
};
694713
let place = unwrap_or_return_codegen_unimplemented_stmt!(
695714
self,
696715
self.codegen_place(place)
697716
)
698717
.goto_expr;
699718
self.codegen_get_niche(place, offset, discr_ty)
700-
.assign(value, Location::none())
719+
.assign(value, location)
701720
} else {
702-
Stmt::skip(Location::none())
721+
Stmt::skip(location)
703722
}
704723
}
705724
},
706725
}
707726
}
708-
StatementKind::StorageLive(_) => Stmt::skip(Location::none()), // TODO: fix me
709-
StatementKind::StorageDead(_) => Stmt::skip(Location::none()), // TODO: fix me
727+
StatementKind::StorageLive(_) => Stmt::skip(location), // TODO: fix me
728+
StatementKind::StorageDead(_) => Stmt::skip(location), // TODO: fix me
710729
StatementKind::CopyNonOverlapping(box mir::CopyNonOverlapping {
711730
ref src,
712731
ref dst,
@@ -719,26 +738,21 @@ impl<'tcx> GotocCtx<'tcx> {
719738
let sz = Expr::int_constant(sz, Type::size_t());
720739
let n = sz.mul(count);
721740
let dst = dst.cast_to(Type::void_pointer());
722-
let e = BuiltinFn::Memcpy.call(vec![dst, src, n.clone()], Location::none());
741+
let e = BuiltinFn::Memcpy.call(vec![dst, src, n.clone()], location.clone());
723742

724743
// The C implementation of memcpy does not allow an invalid pointer for
725744
// the src/dst, but the LLVM implementation specifies that a copy with
726745
// length zero is a no-op. This comes up specifically when handling
727746
// the empty string; CBMC will fail on passing a reference to empty
728747
// string unless we codegen this zero check.
729748
// https://llvm.org/docs/LangRef.html#llvm-memcpy-intrinsic
730-
Stmt::if_then_else(
731-
n.is_zero().not(),
732-
e.as_stmt(Location::none()),
733-
None,
734-
Location::none(),
735-
)
749+
Stmt::if_then_else(n.is_zero().not(), e.as_stmt(location.clone()), None, location)
736750
}
737751
StatementKind::FakeRead(_)
738752
| StatementKind::Retag(_, _)
739753
| StatementKind::AscribeUserType(_, _)
740754
| StatementKind::Nop
741-
| StatementKind::Coverage { .. } => Stmt::skip(Location::none()),
755+
| StatementKind::Coverage { .. } => Stmt::skip(location),
742756
}
743757
.with_location(self.codegen_span(&stmt.source_info.span))
744758
}

kani-compiler/src/codegen_cprover_gotoc/codegen/typ.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1206,7 +1206,7 @@ impl<'tcx> GotocCtx<'tcx> {
12061206
pub fn codegen_enum_discr_typ(&self, ty: Ty<'tcx>) -> Ty<'tcx> {
12071207
let layout = self.layout_of(ty);
12081208
match &layout.variants {
1209-
Variants::Multiple { tag, .. } => self.codegen_prim_typ(tag.value),
1209+
Variants::Multiple { tag, .. } => self.codegen_prim_typ(tag.primitive()),
12101210
_ => unreachable!("only enum has discriminant"),
12111211
}
12121212
}
@@ -1263,7 +1263,7 @@ impl<'tcx> GotocCtx<'tcx> {
12631263
_ => unreachable!(),
12641264
};
12651265

1266-
let rustc_target::abi::Scalar { value: prim_type, .. } = element;
1266+
let prim_type = element.primitive();
12671267
let rust_type = self.codegen_prim_typ(prim_type);
12681268
let cbmc_type = self.codegen_ty(rust_type);
12691269

0 commit comments

Comments
 (0)