Skip to content

Commit 6f7aa65

Browse files
authored
1 parent 2a09d79 commit 6f7aa65

File tree

37 files changed

+181
-131
lines changed

37 files changed

+181
-131
lines changed

cprover_bindings/src/goto_program/expr.rs

+11
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,17 @@ impl Expr {
851851
Expr::struct_expr_with_explicit_padding(typ, fields, values)
852852
}
853853

854+
/// Initializer for a zero sized type (ZST).
855+
/// Since this is a ZST, we call nondet to simplify everything.
856+
pub fn init_unit(typ: Type, symbol_table: &SymbolTable) -> Self {
857+
assert!(
858+
typ.is_struct_tag(),
859+
"Zero sized types should be represented as struct: but found: {typ:?}"
860+
);
861+
assert_eq!(typ.sizeof_in_bits(symbol_table), 0);
862+
Expr::nondet(typ)
863+
}
864+
854865
/// `identifier`
855866
pub fn symbol_expression<T: Into<InternedString>>(identifier: T, typ: Type) -> Self {
856867
let identifier = identifier.into();

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,11 @@ impl<'tcx> GotocCtx<'tcx> {
154154
if self.queries.get_check_assertion_reachability() {
155155
// Generate a unique ID for the assert
156156
let assert_id = self.next_check_id();
157-
// Generate a message for the reachability check that includes the unique ID
158-
let reach_msg = assert_id.clone();
159157
// Also add the unique ID as a prefix to the assert message so that it can be
160158
// easily paired with the reachability check
161159
let msg = GotocCtx::add_prefix_to_msg(&msg, &assert_id);
160+
// Generate a message for the reachability check that includes the unique ID
161+
let reach_msg = assert_id;
162162
// inject a reachability check, which is a (non-blocking)
163163
// assert(false) whose failure indicates that this line is reachable.
164164
// The property class (`PropertyClass:ReachabilityCheck`) is used by

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<'tcx> GotocCtx<'tcx> {
5151
var_type,
5252
self.codegen_span(&ldata.source_info.span),
5353
)
54-
.with_is_hidden(!ldata.is_user_variable())
54+
.with_is_hidden(!self.is_user_variable(&lc))
5555
.with_is_parameter((idx > 0 && idx <= num_args) && !self.is_zst(var_ty));
5656
let sym_e = sym.to_expr();
5757
self.symbol_table.insert(sym);

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

+14-5
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use cbmc::goto_program::{
99
Location, Stmt, Type, ARITH_OVERFLOW_OVERFLOWED_FIELD, ARITH_OVERFLOW_RESULT_FIELD,
1010
};
1111
use rustc_middle::mir::{BasicBlock, Operand, Place};
12-
use rustc_middle::ty::layout::LayoutOf;
12+
use rustc_middle::ty::layout::{LayoutOf, ValidityRequirement};
1313
use rustc_middle::ty::{self, Ty};
1414
use rustc_middle::ty::{Instance, InstanceDef};
1515
use rustc_span::Span;
@@ -753,7 +753,7 @@ impl<'tcx> GotocCtx<'tcx> {
753753
/// layout is invalid so we get a message that mentions the offending type.
754754
///
755755
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_inhabited.html>
756-
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_uninit_valid.html>
756+
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_mem_uninitialized_valid.html>
757757
/// <https://doc.rust-lang.org/std/intrinsics/fn.assert_zero_valid.html>
758758
fn codegen_assert_intrinsic(
759759
&mut self,
@@ -781,7 +781,10 @@ impl<'tcx> GotocCtx<'tcx> {
781781
// Then we check if the type allows "raw" initialization for the cases
782782
// where memory is zero-initialized or entirely uninitialized
783783
if intrinsic == "assert_zero_valid"
784-
&& !self.tcx.permits_zero_init(param_env_and_type).ok().unwrap()
784+
&& !self
785+
.tcx
786+
.check_validity_requirement((ValidityRequirement::Zero, param_env_and_type))
787+
.unwrap()
785788
{
786789
return self.codegen_fatal_error(
787790
PropertyClass::SafetyCheck,
@@ -790,8 +793,14 @@ impl<'tcx> GotocCtx<'tcx> {
790793
);
791794
}
792795

793-
if intrinsic == "assert_uninit_valid"
794-
&& !self.tcx.permits_uninit_init(param_env_and_type).ok().unwrap()
796+
if intrinsic == "assert_mem_uninitialized_valid"
797+
&& !self
798+
.tcx
799+
.check_validity_requirement((
800+
ValidityRequirement::UninitMitigated0x01Fill,
801+
param_env_and_type,
802+
))
803+
.unwrap()
795804
{
796805
return self.codegen_fatal_error(
797806
PropertyClass::SafetyCheck,

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ impl<'tcx> GotocCtx<'tcx> {
141141
ConstValue::ZeroSized => match lit_ty.kind() {
142142
// Rust "function items" (not closures, not function pointers, see `codegen_fndef`)
143143
ty::FnDef(d, substs) => self.codegen_fndef(*d, substs, span),
144-
_ => unimplemented!(),
144+
_ => Expr::init_unit(self.codegen_ty(lit_ty), &self.symbol_table),
145145
},
146146
}
147147
}
@@ -310,7 +310,7 @@ impl<'tcx> GotocCtx<'tcx> {
310310
}
311311
} else {
312312
// otherwise, there is just one field, which is stored as the scalar data
313-
let field = &variant.fields[0];
313+
let field = &variant.fields[0usize.into()];
314314
let fty = field.ty(self.tcx, subst);
315315

316316
let overall_t = self.codegen_ty(ty);
@@ -336,7 +336,7 @@ impl<'tcx> GotocCtx<'tcx> {
336336
&self.symbol_table,
337337
),
338338
1 => {
339-
let fty = variant.fields[0].ty(self.tcx, subst);
339+
let fty = variant.fields[0usize.into()].ty(self.tcx, subst);
340340
self.codegen_single_variant_single_field(
341341
s, span, overall_t, fty,
342342
)

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

+6-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@ use crate::codegen_cprover_gotoc::utils::{dynamic_fat_ptr, slice_fat_ptr};
1111
use crate::codegen_cprover_gotoc::GotocCtx;
1212
use crate::unwrap_or_return_codegen_unimplemented;
1313
use cbmc::goto_program::{Expr, Location, Type};
14+
use rustc_abi::FieldIdx;
1415
use rustc_hir::Mutability;
1516
use rustc_middle::ty::layout::LayoutOf;
1617
use rustc_middle::{
17-
mir::{Field, Local, Place, ProjectionElem},
18+
mir::{Local, Place, ProjectionElem},
1819
ty::{self, Ty, TypeAndMut, VariantDef},
1920
};
2021
use rustc_target::abi::{TagEncoding, VariantIdx, Variants};
@@ -238,7 +239,7 @@ impl<'tcx> GotocCtx<'tcx> {
238239
&mut self,
239240
res: Expr,
240241
t: TypeOrVariant<'tcx>,
241-
f: &Field,
242+
f: &FieldIdx,
242243
) -> Result<Expr, UnimplementedData> {
243244
match t {
244245
TypeOrVariant::Type(t) => {
@@ -278,12 +279,12 @@ impl<'tcx> GotocCtx<'tcx> {
278279
}
279280
// if we fall here, then we are handling either a struct or a union
280281
ty::Adt(def, _) => {
281-
let field = &def.variants().raw[0].fields[f.index()];
282+
let field = &def.variants().raw[0].fields[*f];
282283
Ok(res.member(&field.name.to_string(), &self.symbol_table))
283284
}
284285
ty::Closure(..) => Ok(res.member(&f.index().to_string(), &self.symbol_table)),
285286
ty::Generator(..) => {
286-
let field_name = self.generator_field_name(f.index());
287+
let field_name = self.generator_field_name(f.as_usize());
287288
Ok(res
288289
.member("direct_fields", &self.symbol_table)
289290
.member(field_name, &self.symbol_table))
@@ -293,7 +294,7 @@ impl<'tcx> GotocCtx<'tcx> {
293294
}
294295
// if we fall here, then we are handling an enum
295296
TypeOrVariant::Variant(v) => {
296-
let field = &v.fields[f.index()];
297+
let field = &v.fields[*f];
297298
Ok(res.member(&field.name.to_string(), &self.symbol_table))
298299
}
299300
TypeOrVariant::GeneratorVariant(_var_idx) => {

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

+20-10
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ use cbmc::goto_program::{
1717
use cbmc::MachineModel;
1818
use cbmc::{btree_string_map, InternString, InternedString};
1919
use num::bigint::BigInt;
20+
use rustc_abi::FieldIdx;
21+
use rustc_index::vec::IndexVec;
2022
use rustc_middle::mir::{AggregateKind, BinOp, CastKind, NullOp, Operand, Place, Rvalue, UnOp};
2123
use rustc_middle::ty::adjustment::PointerCast;
2224
use rustc_middle::ty::layout::LayoutOf;
@@ -321,7 +323,11 @@ impl<'tcx> GotocCtx<'tcx> {
321323
}
322324

323325
/// Create an initializer for a generator struct.
324-
fn codegen_rvalue_generator(&mut self, operands: &[Operand<'tcx>], ty: Ty<'tcx>) -> Expr {
326+
fn codegen_rvalue_generator(
327+
&mut self,
328+
operands: &IndexVec<FieldIdx, Operand<'tcx>>,
329+
ty: Ty<'tcx>,
330+
) -> Expr {
325331
let layout = self.layout_of(ty);
326332
let discriminant_field = match &layout.variants {
327333
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => tag_field,
@@ -341,7 +347,7 @@ impl<'tcx> GotocCtx<'tcx> {
341347
if idx == *discriminant_field {
342348
Expr::int_constant(0, self.codegen_ty(field_ty))
343349
} else {
344-
self.codegen_operand(&operands[idx])
350+
self.codegen_operand(&operands[idx.into()])
345351
}
346352
})
347353
.collect(),
@@ -358,7 +364,7 @@ impl<'tcx> GotocCtx<'tcx> {
358364
fn codegen_rvalue_enum_aggregate(
359365
&mut self,
360366
variant_index: VariantIdx,
361-
operands: &[Operand<'tcx>],
367+
operands: &IndexVec<FieldIdx, Operand<'tcx>>,
362368
res_ty: Ty<'tcx>,
363369
loc: Location,
364370
) -> Expr {
@@ -400,7 +406,7 @@ impl<'tcx> GotocCtx<'tcx> {
400406
variant_expr.typ().clone(),
401407
fields
402408
.index_by_increasing_offset()
403-
.map(|idx| self.codegen_operand(&operands[idx]))
409+
.map(|idx| self.codegen_operand(&operands[idx.into()]))
404410
.collect(),
405411
&self.symbol_table,
406412
);
@@ -419,7 +425,7 @@ impl<'tcx> GotocCtx<'tcx> {
419425
fn codegen_rvalue_aggregate(
420426
&mut self,
421427
aggregate: &AggregateKind<'tcx>,
422-
operands: &[Operand<'tcx>],
428+
operands: &IndexVec<FieldIdx, Operand<'tcx>>,
423429
res_ty: Ty<'tcx>,
424430
loc: Location,
425431
) -> Expr {
@@ -449,8 +455,8 @@ impl<'tcx> GotocCtx<'tcx> {
449455
let components = typ.lookup_components(&self.symbol_table).unwrap();
450456
Expr::union_expr(
451457
typ,
452-
components[active_field_index].name(),
453-
self.codegen_operand(&operands[0]),
458+
components[active_field_index.as_usize()].name(),
459+
self.codegen_operand(&operands[0usize.into()]),
454460
&self.symbol_table,
455461
)
456462
}
@@ -464,7 +470,7 @@ impl<'tcx> GotocCtx<'tcx> {
464470
.fields
465471
.index_by_increasing_offset()
466472
.map(|idx| {
467-
let cgo = self.codegen_operand(&operands[idx]);
473+
let cgo = self.codegen_operand(&operands[idx.into()]);
468474
// The input operand might actually be a one-element array, as seen
469475
// when running assess on firecracker.
470476
if *cgo.typ() == vector_element_type {
@@ -487,7 +493,7 @@ impl<'tcx> GotocCtx<'tcx> {
487493
layout
488494
.fields
489495
.index_by_increasing_offset()
490-
.map(|idx| self.codegen_operand(&operands[idx]))
496+
.map(|idx| self.codegen_operand(&operands[idx.into()]))
491497
.collect(),
492498
&self.symbol_table,
493499
)
@@ -537,6 +543,10 @@ impl<'tcx> GotocCtx<'tcx> {
537543
let t = self.monomorphize(*t);
538544
self.codegen_pointer_cast(k, e, t, loc)
539545
}
546+
Rvalue::Cast(CastKind::Transmute, operand, ty) => {
547+
let goto_typ = self.codegen_ty(self.monomorphize(*ty));
548+
self.codegen_operand(operand).transmute_to(goto_typ, &self.symbol_table)
549+
}
540550
Rvalue::BinaryOp(op, box (ref e1, ref e2)) => {
541551
self.codegen_rvalue_binary_op(op, e1, e2, loc)
542552
}
@@ -636,7 +646,7 @@ impl<'tcx> GotocCtx<'tcx> {
636646
// See also the cranelift backend:
637647
// https://github.com/rust-lang/rust/blob/05d22212e89588e7c443cc6b9bc0e4e02fdfbc8d/compiler/rustc_codegen_cranelift/src/discriminant.rs#L116
638648
let offset = match &layout.fields {
639-
FieldsShape::Arbitrary { offsets, .. } => offsets[0],
649+
FieldsShape::Arbitrary { offsets, .. } => offsets[0usize.into()],
640650
_ => unreachable!("niche encoding must have arbitrary fields"),
641651
};
642652

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

+17-8
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ impl<'tcx> GotocCtx<'tcx> {
8686
location,
8787
)
8888
}
89+
StatementKind::PlaceMention(_) => todo!(),
8990
StatementKind::FakeRead(_)
9091
| StatementKind::Retag(_, _)
9192
| StatementKind::AscribeUserType(_, _)
@@ -122,8 +123,8 @@ impl<'tcx> GotocCtx<'tcx> {
122123
loc,
123124
"https://github.com/model-checking/kani/issues/692",
124125
),
125-
TerminatorKind::Abort => self.codegen_mimic_unimplemented(
126-
"TerminatorKind::Abort",
126+
TerminatorKind::Terminate => self.codegen_mimic_unimplemented(
127+
"TerminatorKind::Terminate",
127128
loc,
128129
"https://github.com/model-checking/kani/issues/692",
129130
),
@@ -165,6 +166,10 @@ impl<'tcx> GotocCtx<'tcx> {
165166
// "index out of bounds: the length is {len} but the index is {index}",
166167
// but CBMC only accepts static messages so we don't add values to the message.
167168
"index out of bounds: the length is less than or equal to the given index"
169+
} else if let AssertKind::MisalignedPointerDereference { .. } = msg {
170+
// Misaligned pointer dereference check messages is also a runtime messages.
171+
// Generate a generic one here.
172+
"misaligned pointer dereference: address must be a multiple of its type's alignment"
168173
} else {
169174
// For all other assert kind we can get the static message.
170175
msg.description()
@@ -187,9 +192,7 @@ impl<'tcx> GotocCtx<'tcx> {
187192
loc,
188193
)
189194
}
190-
TerminatorKind::DropAndReplace { .. }
191-
| TerminatorKind::FalseEdge { .. }
192-
| TerminatorKind::FalseUnwind { .. } => {
195+
TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } => {
193196
unreachable!("drop elaboration removes these TerminatorKind")
194197
}
195198
TerminatorKind::Yield { .. } | TerminatorKind::GeneratorDrop => {
@@ -232,19 +235,23 @@ impl<'tcx> GotocCtx<'tcx> {
232235
// DISCRIMINANT - val:255 ty:i8
233236
// DISCRIMINANT - val:0 ty:i8
234237
// DISCRIMINANT - val:1 ty:i8
235-
let discr = Expr::int_constant(discr.val, self.codegen_ty(discr_t));
236-
self.codegen_discriminant_field(dest_expr, dest_ty).assign(discr, location)
238+
trace!(?discr, ?discr_t, ?dest_ty, "codegen_set_discriminant direct");
239+
// The discr.ty doesn't always match the tag type. Explicitly cast if needed.
240+
let discr_expr = Expr::int_constant(discr.val, self.codegen_ty(discr.ty))
241+
.cast_to(self.codegen_ty(discr_t));
242+
self.codegen_discriminant_field(dest_expr, dest_ty).assign(discr_expr, location)
237243
}
238244
TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
239245
if *untagged_variant != variant_index {
240246
let offset = match &layout.fields {
241-
FieldsShape::Arbitrary { offsets, .. } => offsets[0],
247+
FieldsShape::Arbitrary { offsets, .. } => offsets[0usize.into()],
242248
_ => unreachable!("niche encoding must have arbitrary fields"),
243249
};
244250
let discr_ty = self.codegen_enum_discr_typ(dest_ty);
245251
let discr_ty = self.codegen_ty(discr_ty);
246252
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
247253
let niche_value = (niche_value as u128).wrapping_add(*niche_start);
254+
trace!(val=?niche_value, typ=?discr_ty, "codegen_set_discriminant niche");
248255
let value = if niche_value == 0
249256
&& matches!(tag.primitive(), Primitive::Pointer(_))
250257
{
@@ -548,6 +555,7 @@ impl<'tcx> GotocCtx<'tcx> {
548555
// Normal, non-virtual function calls
549556
InstanceDef::Item(..)
550557
| InstanceDef::DropGlue(_, Some(_))
558+
| InstanceDef::FnPtrAddrShim(_, _)
551559
| InstanceDef::Intrinsic(..)
552560
| InstanceDef::FnPtrShim(..)
553561
| InstanceDef::VTableShim(..)
@@ -562,6 +570,7 @@ impl<'tcx> GotocCtx<'tcx> {
562570
.with_location(loc),
563571
]
564572
}
573+
InstanceDef::ThreadLocalShim(_) => todo!(),
565574
};
566575
stmts.push(self.codegen_end_call(target.as_ref(), loc));
567576
Stmt::block(stmts, loc)

0 commit comments

Comments
 (0)