Skip to content

Commit abdb9a0

Browse files
celinvaltedinski
authored andcommitted
Inject runtime error for type mismatch in projection (rust-lang#1086)
This is to mitigate potentially wrong code generation detected by our type mismatch logic. Eventually we want to enable this assertion and fail at runtime, but this currently affects the compilation of std. Note: I had to fix the projection error handling for codegen_place. This wasn't working if the failure was in the middle of the projection.
1 parent 5c4314a commit abdb9a0

File tree

3 files changed

+51
-19
lines changed

3 files changed

+51
-19
lines changed

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

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,13 @@ impl<'tcx> ProjectedPlace<'tcx> {
146146
}
147147
}
148148

149-
pub fn new(
149+
pub fn try_new(
150150
goto_expr: Expr,
151151
mir_typ_or_variant: TypeOrVariant<'tcx>,
152152
fat_ptr_goto_expr: Option<Expr>,
153153
fat_ptr_mir_typ: Option<Ty<'tcx>>,
154154
ctx: &mut GotocCtx<'tcx>,
155-
) -> Self {
155+
) -> Result<Self, UnimplementedData> {
156156
let mir_typ_or_variant = mir_typ_or_variant.monomorphize(ctx);
157157
let fat_ptr_mir_typ = fat_ptr_mir_typ.map(|t| ctx.monomorphize(t));
158158
if let Some(fat_ptr) = &fat_ptr_goto_expr {
@@ -173,6 +173,12 @@ impl<'tcx> ProjectedPlace<'tcx> {
173173
"Unexpected type mismatch in projection:\n{:?}\nExpr type\n{:?}\nType from MIR\n{:?}",
174174
goto_expr, expr_ty, ty_from_mir
175175
);
176+
return Err(UnimplementedData::new(
177+
"Projection mismatch",
178+
"https://github.com/model-checking/kani/issues/277",
179+
ty_from_mir,
180+
*goto_expr.location(),
181+
));
176182
}
177183

178184
assert!(
@@ -181,7 +187,7 @@ impl<'tcx> ProjectedPlace<'tcx> {
181187
&fat_ptr_goto_expr,
182188
&fat_ptr_mir_typ
183189
);
184-
ProjectedPlace { goto_expr, mir_typ_or_variant, fat_ptr_goto_expr, fat_ptr_mir_typ }
190+
Ok(ProjectedPlace { goto_expr, mir_typ_or_variant, fat_ptr_goto_expr, fat_ptr_mir_typ })
185191
}
186192
}
187193

@@ -395,18 +401,18 @@ impl<'tcx> GotocCtx<'tcx> {
395401
_ => inner_goto_expr.dereference(),
396402
};
397403
let typ = TypeOrVariant::Type(inner_mir_typ);
398-
Ok(ProjectedPlace::new(expr, typ, fat_ptr_goto_expr, fat_ptr_mir_typ, self))
404+
ProjectedPlace::try_new(expr, typ, fat_ptr_goto_expr, fat_ptr_mir_typ, self)
399405
}
400406
ProjectionElem::Field(f, t) => {
401407
let typ = TypeOrVariant::Type(t);
402408
let expr = self.codegen_field(before.goto_expr, before.mir_typ_or_variant, &f)?;
403-
Ok(ProjectedPlace::new(
409+
ProjectedPlace::try_new(
404410
expr,
405411
typ,
406412
before.fat_ptr_goto_expr,
407413
before.fat_ptr_mir_typ,
408414
self,
409-
))
415+
)
410416
}
411417
ProjectionElem::Index(i) => {
412418
let base_type = before.mir_typ();
@@ -420,16 +426,16 @@ impl<'tcx> GotocCtx<'tcx> {
420426
ty::Slice(..) => before.goto_expr.index(idxe),
421427
_ => unreachable!("must index an array"),
422428
};
423-
Ok(ProjectedPlace::new(
429+
ProjectedPlace::try_new(
424430
expr,
425431
typ,
426432
before.fat_ptr_goto_expr,
427433
before.fat_ptr_mir_typ,
428434
self,
429-
))
435+
)
430436
}
431437
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
432-
Ok(self.codegen_constant_index(before, offset, min_length, from_end))
438+
self.codegen_constant_index(before, offset, min_length, from_end)
433439
}
434440
// Best effort to codegen subslice projection.
435441
// Full support to be added in
@@ -476,13 +482,13 @@ impl<'tcx> GotocCtx<'tcx> {
476482
let from_elem = before.goto_expr.index(index);
477483
let data = from_elem.address_of();
478484
let fat_ptr = slice_fat_ptr(goto_type, data, len, &self.symbol_table);
479-
Ok(ProjectedPlace::new(
485+
ProjectedPlace::try_new(
480486
fat_ptr.clone(),
481487
TypeOrVariant::Type(ptr_typ),
482488
Some(fat_ptr),
483489
Some(ptr_typ),
484490
self,
485-
))
491+
)
486492
}
487493
_ => unreachable!("must be array or slice"),
488494
}
@@ -507,13 +513,13 @@ impl<'tcx> GotocCtx<'tcx> {
507513
TagEncoding::Niche { .. } => before.goto_expr,
508514
},
509515
};
510-
Ok(ProjectedPlace::new(
516+
ProjectedPlace::try_new(
511517
expr,
512518
typ,
513519
before.fat_ptr_goto_expr,
514520
before.fat_ptr_mir_typ,
515521
self,
516-
))
522+
)
517523
}
518524
_ => unreachable!("it's a bug to reach here!"),
519525
}
@@ -535,10 +541,21 @@ impl<'tcx> GotocCtx<'tcx> {
535541
let initial_expr = self.codegen_local(p.local);
536542
let initial_typ = TypeOrVariant::Type(self.local_ty(p.local));
537543
debug!(?initial_typ, ?initial_expr, "codegen_place");
538-
let initial_projection = ProjectedPlace::new(initial_expr, initial_typ, None, None, self);
539-
p.projection
544+
let initial_projection =
545+
ProjectedPlace::try_new(initial_expr, initial_typ, None, None, self);
546+
let result = p
547+
.projection
540548
.iter()
541-
.fold(Ok(initial_projection), |accum, proj| self.codegen_projection(accum, proj))
549+
.fold(initial_projection, |accum, proj| self.codegen_projection(accum, proj));
550+
match result {
551+
Err(data) => Err(UnimplementedData::new(
552+
&data.operation,
553+
&data.bug_url,
554+
self.codegen_ty(self.place_ty(p)),
555+
data.loc,
556+
)),
557+
_ => result,
558+
}
542559
}
543560

544561
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/mir/enum.ProjectionElem.html
@@ -555,7 +572,7 @@ impl<'tcx> GotocCtx<'tcx> {
555572
offset: u64,
556573
min_length: u64,
557574
from_end: bool,
558-
) -> ProjectedPlace<'tcx> {
575+
) -> Result<ProjectedPlace<'tcx>, UnimplementedData> {
559576
match before.mir_typ().kind() {
560577
//TODO, ask on zulip if we can ever have from_end here?
561578
ty::Array(elemt, length) => {
@@ -565,7 +582,7 @@ impl<'tcx> GotocCtx<'tcx> {
565582
let idxe = Expr::int_constant(idx, Type::ssize_t());
566583
let expr = self.codegen_idx_array(before.goto_expr, idxe);
567584
let typ = TypeOrVariant::Type(*elemt);
568-
ProjectedPlace::new(
585+
ProjectedPlace::try_new(
569586
expr,
570587
typ,
571588
before.fat_ptr_goto_expr,
@@ -585,7 +602,7 @@ impl<'tcx> GotocCtx<'tcx> {
585602
};
586603
let expr = before.goto_expr.plus(idxe).dereference();
587604
let typ = TypeOrVariant::Type(*elemt);
588-
ProjectedPlace::new(
605+
ProjectedPlace::try_new(
589606
expr,
590607
typ,
591608
before.fat_ptr_goto_expr,
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Failed Checks: Projection mismatch is not currently supported by Kani. Please post your example at https://github.com/model-checking/kani/issues/277
2+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
4+
//! This test checks the result of using Iterator::flat_map. Note that the same test exists inside
5+
//! kani suite. This test is just to ensure we error when there is a projection issue.
6+
7+
#[kani::proof]
8+
#[kani::unwind(3)]
9+
fn check_flat_map_char() {
10+
let hello = ["H", "i"];
11+
let length = hello.iter().flat_map(|s| s.chars()).count();
12+
assert_eq!(length, 2);
13+
}

0 commit comments

Comments
 (0)