Skip to content

Commit cae7aca

Browse files
authored
Add Poison to the Kani-GotoC AST (#1469)
* Add a comment field to Location::Loc, set that field for Deinit * Use a poison expression instead * use "poison" instead of "deinit", fix various comments * fix copy/paste mistake * Deinit statement instead of Poison expression * fix remaining merge conflicts * regression tests not ran yet * one test is broken in the regression test suite * add various comments * more comments
1 parent e1a1fe1 commit cae7aca

File tree

7 files changed

+41
-4
lines changed

7 files changed

+41
-4
lines changed

cprover_bindings/src/goto_program/expr.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,11 @@ impl Expr {
14931493
Stmt::assign(self, rhs, loc)
14941494
}
14951495

1496+
/// Shorthand to build a `Deinit(self)` statement. See `StmtBody::Deinit`
1497+
pub fn deinit(self, loc: Location) -> Stmt {
1498+
Stmt::deinit(self, loc)
1499+
}
1500+
14961501
/// `if (self) { t } else { e }` or `if (self) { t }`
14971502
pub fn if_then_else(self, t: Stmt, e: Option<Stmt>, loc: Location) -> Stmt {
14981503
Stmt::if_then_else(self, t, e, loc)

cprover_bindings/src/goto_program/stmt.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ pub enum StmtBody {
6262
lhs: Expr, // SymbolExpr
6363
value: Option<Expr>,
6464
},
65+
/// Marks the target place as uninitialized.
66+
Deinit(Expr),
6567
/// `e;`
6668
Expression(Expr),
6769
// `for (init; cond; update) {body}`
@@ -237,6 +239,11 @@ impl Stmt {
237239
stmt!(Decl { lhs, value }, loc)
238240
}
239241

242+
/// `Deinit(place)`, see `StmtBody::Deinit`.
243+
pub fn deinit(place: Expr, loc: Location) -> Self {
244+
stmt!(Deinit(place), loc)
245+
}
246+
240247
/// `e;`
241248
pub fn code_expression(e: Expr, loc: Location) -> Self {
242249
stmt!(Expression(e), loc)

cprover_bindings/src/goto_program/symtab_transformer/gen_c_transformer/nondet_transformer.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ pub struct NondetTransformer {
1111
nondet_types: HashMap<String, Type>,
1212
}
1313

14+
// Note: this replaces every occurence of a Nondet expression by an equivalent function call.
15+
// Since the introduction of StmtBody::Deinit, some Nondet expressions only appear
16+
// at Irep generating time. Such expressions will not be substituted by this transformer.
17+
1418
impl NondetTransformer {
1519
/// Transform all identifiers in the symbol table to be valid C identifiers;
1620
/// perform other clean-up operations to make valid C code.

cprover_bindings/src/goto_program/symtab_transformer/transformer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,6 @@ pub trait Transformer: Sized {
412412
transformed_lhs.member(field, self.symbol_table())
413413
}
414414

415-
/// Transforms a CPROVER nondet call (`__nondet()`)
416415
fn transform_expr_nondet(&mut self, typ: &Type) -> Expr {
417416
let transformed_typ = self.transform_type(typ);
418417
Expr::nondet(transformed_typ)
@@ -520,6 +519,7 @@ pub trait Transformer: Sized {
520519
StmtBody::Break => self.transform_stmt_break(),
521520
StmtBody::Continue => self.transform_stmt_continue(),
522521
StmtBody::Decl { lhs, value } => self.transform_stmt_decl(lhs, value),
522+
StmtBody::Deinit(place) => self.transform_stmt_deinit(place),
523523
StmtBody::Expression(expr) => self.transform_stmt_expression(expr),
524524
StmtBody::For { init, cond, update, body } => {
525525
self.transform_stmt_for(init, cond, update, body)
@@ -598,6 +598,11 @@ pub trait Transformer: Sized {
598598
Stmt::decl(transformed_lhs, transformed_value, Location::none())
599599
}
600600

601+
fn transform_stmt_deinit(&mut self, place: &Expr) -> Stmt {
602+
let transformed_place = self.transform_expr(place);
603+
Stmt::deinit(transformed_place, Location::none())
604+
}
605+
601606
/// Transform an expression stmt (`e;`)
602607
fn transform_stmt_expression(&mut self, expr: &Expr) -> Stmt {
603608
let transformed_expr = self.transform_expr(expr);

cprover_bindings/src/irep/irep.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ impl Irep {
4444
}
4545
}
4646

47+
/// Adds a `comment` sub to the irep.
48+
/// Note that there might be comments both on the irep itself and
49+
/// inside the location sub of the irep.
50+
pub fn with_comment<T: Into<InternedString>>(self, c: T) -> Self {
51+
self.with_named_sub(IrepId::Comment, Irep::just_string_id(c))
52+
}
53+
4754
pub fn with_named_sub(mut self, key: IrepId, value: Irep) -> Self {
4855
if !value.is_nil() {
4956
self.named_sub.insert(key, value);

cprover_bindings/src/irep/to_irep.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,13 @@ impl ToIrep for StmtBody {
430430
code_irep(IrepId::Decl, vec![lhs.to_irep(mm)])
431431
}
432432
}
433+
StmtBody::Deinit(place) => {
434+
// CBMC doesn't yet have a notion of poison (https://github.com/diffblue/cbmc/issues/7014)
435+
// So we translate identically to `nondet` here, but add a comment noting we wish it were poison
436+
// potentially for other backends to pick up and treat specially.
437+
code_irep(IrepId::Assign, vec![place.to_irep(mm), place.typ().nondet().to_irep(mm)])
438+
.with_comment("deinit")
439+
}
433440
StmtBody::Expression(e) => code_irep(IrepId::Expression, vec![e.to_irep(mm)]),
434441
StmtBody::For { init, cond, update, body } => code_irep(
435442
IrepId::For,

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ impl<'tcx> GotocCtx<'tcx> {
5858
}
5959
StatementKind::Deinit(place) => {
6060
// From rustc doc: "This writes `uninit` bytes to the entire place."
61-
// Thus, we assign nondet() value to the entire place.
61+
// Our model of GotoC has a similar statement, which is later lowered
62+
// to assigning a Nondet in CBMC, with a comment specifying that it
63+
// corresponds to a Deinit.
6264
let dst_mir_ty = self.place_ty(place);
6365
let dst_type = self.codegen_ty(dst_mir_ty);
6466
let layout = self.layout_of(dst_mir_ty);
@@ -68,7 +70,7 @@ impl<'tcx> GotocCtx<'tcx> {
6870
} else {
6971
unwrap_or_return_codegen_unimplemented_stmt!(self, self.codegen_place(place))
7072
.goto_expr
71-
.assign(dst_type.nondet(), location)
73+
.deinit(location)
7274
}
7375
}
7476
StatementKind::SetDiscriminant { place, variant_index } => {
@@ -157,7 +159,7 @@ impl<'tcx> GotocCtx<'tcx> {
157159
| StatementKind::Nop
158160
| StatementKind::Coverage { .. } => Stmt::skip(location),
159161
}
160-
.with_location(self.codegen_span(&stmt.source_info.span))
162+
.with_location(location)
161163
}
162164

163165
/// Generate Goto-c for MIR [Terminator] statements.

0 commit comments

Comments
 (0)