Skip to content

Commit e0734ec

Browse files
authored
Merge pull request #823 from xldenis/sound-ghost-type
Avoid unsound type definitions with ghost fields
2 parents ea7b516 + 4e3d4d8 commit e0734ec

File tree

96 files changed

+1598
-1097
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

96 files changed

+1598
-1097
lines changed

creusot-contracts/src/logic/ops.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ impl<T> IndexLogic<Int> for Ghost<Seq<T>> {
3333
type Item = T;
3434

3535
#[logic]
36-
#[trusted]
37-
#[open(self)]
38-
#[creusot::builtins = "seq.Seq.get"]
39-
fn index_logic(self, _: Int) -> Self::Item {
40-
absurd
36+
#[open]
37+
#[why3::attr = "inline:trivial"]
38+
fn index_logic(self, ix: Int) -> Self::Item {
39+
pearlite! { (*self)[ix] }
4140
}
4241
}

creusot/src/backend/ty.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ fn build_ty_decl<'tcx>(
372372
.fields
373373
.iter()
374374
.map(|f| {
375-
let ty = field_ty(ctx, names, param_env, f, substs);
375+
let ty = field_ty(ctx, names, param_env, did, f, substs);
376376
Field { ty, ghost: false }
377377
})
378378
.collect();
@@ -410,14 +410,34 @@ fn field_ty<'tcx>(
410410
ctx: &mut Why3Generator<'tcx>,
411411
names: &mut CloneMap<'tcx>,
412412
param_env: ParamEnv<'tcx>,
413+
adt_did: DefId,
413414
field: &FieldDef,
414415
substs: SubstsRef<'tcx>,
415416
) -> MlT {
416417
let ty = field.ty(ctx.tcx, substs);
417418
let ty = ctx.try_normalize_erasing_regions(param_env, ty).unwrap_or(ty);
419+
420+
if !validate_field_ty(ctx, adt_did, ty) {
421+
ctx.crash_and_error(ctx.def_span(field.did), "Illegal use of the Ghost type")
422+
}
423+
418424
translate_ty_inner(TyTranslation::Declaration, ctx, names, ctx.def_span(field.did), ty)
419425
}
420426

427+
fn validate_field_ty<'tcx>(ctx: &mut Why3Generator<'tcx>, adt_did: DefId, ty: Ty<'tcx>) -> bool {
428+
let tcx = ctx.tcx;
429+
let bg = ctx.binding_group(adt_did);
430+
431+
!ty.walk().filter_map(ty::GenericArg::as_type).any(|ty| {
432+
util::is_ghost_ty(tcx, ty)
433+
&& ty.walk().filter_map(ty::GenericArg::as_type).any(|ty| match ty.kind() {
434+
TyKind::Adt(adt_def, _) => bg.contains(&adt_def.did()),
435+
// TyKind::Param(_) => true,
436+
_ => false,
437+
})
438+
})
439+
}
440+
421441
pub(crate) fn translate_accessor(
422442
ctx: &mut Why3Generator<'_>,
423443
adt_did: DefId,
@@ -457,7 +477,8 @@ pub(crate) fn translate_accessor(
457477
let acc_name = format!("{}_{}", variant.name.as_str().to_ascii_lowercase(), field.name);
458478

459479
let param_env = ctx.param_env(adt_did);
460-
let target_ty = field_ty(ctx, &mut names, param_env, &variant.fields[ix.into()], substs);
480+
let target_ty =
481+
field_ty(ctx, &mut names, param_env, adt_did, &variant.fields[ix.into()], substs);
461482

462483
let variant_arities: Vec<_> = adt_def
463484
.variants()

creusot/src/util.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,15 @@ pub(crate) fn is_ghost_closure<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<
7575
} else { None }
7676
}
7777

78+
pub(crate) fn is_ghost_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
79+
let r: Option<bool> = try {
80+
let adt = ty.ty_adt_def()?;
81+
let builtin = get_builtin(tcx, adt.did())?;
82+
builtin.as_str() == "prelude.Ghost.ghost_ty"
83+
};
84+
r.unwrap_or(false)
85+
}
86+
7887
pub(crate) fn is_spec_logic(tcx: TyCtxt, def_id: DefId) -> bool {
7988
get_attr(tcx.get_attrs_unchecked(def_id), &["creusot", "decl", "spec_logic"]).is_some()
8089
}
File renamed without changes.

creusot/tests/should_fail/bug/436.stderr renamed to creusot/tests/should_fail/bug/436_0.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[creusot]: called Logic function in Ghost context "creusot_contracts::__stubs::fin"
2-
--> 436.rs:10:5
2+
--> 436_0.rs:10:5
33
|
44
10 | pearlite! { *(^x).g }
55
| ^^^^^^^^^^^^^^^^^^^^^
File renamed without changes.

creusot/tests/should_fail/bug/436-1.stderr renamed to creusot/tests/should_fail/bug/436_1.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[creusot]: called Logic function in Ghost context "prophecy"
2-
--> 436-1.rs:15:21
2+
--> 436_1.rs:15:21
33
|
44
15 | b.g = ghost! { !prophecy(b) };
55
| ^^^^^^^^
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
extern crate creusot_contracts;
2+
use creusot_contracts::*;
3+
4+
enum Bad<'a> {
5+
None,
6+
Some(Ghost<&'a mut Bad<'a>>),
7+
}
8+
9+
pub fn test_bad() {
10+
let mut x = Bad::None;
11+
let m = &mut x;
12+
let g = ghost!(m);
13+
*m = Bad::Some(ghost!(*g));
14+
proof_assert!(*m == Bad::Some(g));
15+
proof_assert!(^*g == ^m);
16+
let _ = m;
17+
proof_assert!(^*g == Bad::Some(g));
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error[creusot]: Illegal use of the Ghost type
2+
--> 436_2.rs:6:10
3+
|
4+
6 | Some(Ghost<&'a mut Bad<'a>>),
5+
| ^^^^^^^^^^^^^^^^^^^^^^
6+
7+
error: aborting due to previous error
8+

creusot/tests/should_succeed/100doors/why3session.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<path name=".."/><path name="100doors.mlcfg"/>
88
<theory name="C100doors_F" proved="true">
99
<goal name="f&#39;vc" expl="VC for f" proved="true">
10-
<proof prover="1"><result status="valid" time="0.220000" steps="45798"/></proof>
10+
<proof prover="1"><result status="valid" time="0.220000" steps="45466"/></proof>
1111
</goal>
1212
</theory>
1313
</file>

0 commit comments

Comments
 (0)