77//! then transform its body to be a harness for that function.
88
99use crate :: args:: ReachabilityType ;
10+ use crate :: kani_middle:: attributes:: KaniAttributes ;
1011use crate :: kani_middle:: codegen_units:: CodegenUnit ;
11- use crate :: kani_middle:: kani_functions:: { KaniIntrinsic , KaniModel } ;
12+ use crate :: kani_middle:: kani_functions:: { KaniHook , KaniIntrinsic , KaniModel } ;
1213use crate :: kani_middle:: transform:: body:: { InsertPosition , MutableBody , SourceInstruction } ;
1314use crate :: kani_middle:: transform:: { TransformPass , TransformationType } ;
1415use crate :: kani_queries:: QueryDb ;
1516use rustc_middle:: ty:: TyCtxt ;
17+ use stable_mir:: CrateDef ;
1618use stable_mir:: mir:: mono:: Instance ;
17- use stable_mir:: mir:: { Body , Operand , Place , TerminatorKind } ;
18- use stable_mir:: ty:: { FnDef , GenericArgKind , GenericArgs } ;
19+ use stable_mir:: mir:: { Body , Mutability , Operand , Place , TerminatorKind } ;
20+ use stable_mir:: ty:: { FnDef , GenericArgKind , GenericArgs , RigidTy , Ty } ;
1921use tracing:: debug;
2022
2123#[ derive( Debug ) ]
2224pub struct AutomaticHarnessPass {
2325 /// The FnDef of KaniModel::Any
2426 kani_any : FnDef ,
27+ init_contracts_hook : Instance ,
2528 /// All of the automatic harness Instances that we generated in the CodegenUnits constructor
2629 automatic_harnesses : Vec < Instance > ,
2730}
@@ -37,6 +40,9 @@ impl AutomaticHarnessPass {
3740 let kani_fns = query_db. kani_functions ( ) ;
3841 let harness_intrinsic = * kani_fns. get ( & KaniIntrinsic :: AutomaticHarness . into ( ) ) . unwrap ( ) ;
3942 let kani_any = * kani_fns. get ( & KaniModel :: Any . into ( ) ) . unwrap ( ) ;
43+ let init_contracts_hook = * kani_fns. get ( & KaniHook :: InitContracts . into ( ) ) . unwrap ( ) ;
44+ let init_contracts_hook =
45+ Instance :: resolve ( init_contracts_hook, & GenericArgs ( vec ! [ ] ) ) . unwrap ( ) ;
4046 let automatic_harnesses = unit
4147 . harnesses
4248 . iter ( )
@@ -46,7 +52,7 @@ impl AutomaticHarnessPass {
4652 def == harness_intrinsic
4753 } )
4854 . collect :: < Vec < _ > > ( ) ;
49- Self { kani_any, automatic_harnesses }
55+ Self { kani_any, init_contracts_hook , automatic_harnesses }
5056 }
5157}
5258
@@ -65,7 +71,7 @@ impl TransformPass for AutomaticHarnessPass {
6571 matches ! ( query_db. args( ) . reachability_analysis, ReachabilityType :: AllFns )
6672 }
6773
68- fn transform ( & mut self , _tcx : TyCtxt , body : Body , instance : Instance ) -> ( bool , Body ) {
74+ fn transform ( & mut self , tcx : TyCtxt , body : Body , instance : Instance ) -> ( bool , Body ) {
6975 debug ! ( function=?instance. name( ) , "AutomaticHarnessPass::transform" ) ;
7076
7177 if !self . automatic_harnesses . contains ( & instance) {
@@ -83,6 +89,23 @@ impl TransformPass for AutomaticHarnessPass {
8389 harness_body. clear_body ( TerminatorKind :: Return ) ;
8490 let mut source = SourceInstruction :: Terminator { bb : 0 } ;
8591
92+ // Contract harnesses need a free(NULL) statement, c.f. kani_core::init_contracts().
93+ let attrs = KaniAttributes :: for_def_id ( tcx, def. def_id ( ) ) ;
94+ if attrs. has_contract ( ) {
95+ let ret_local = harness_body. new_local (
96+ Ty :: from_rigid_kind ( RigidTy :: Tuple ( vec ! [ ] ) ) ,
97+ source. span ( harness_body. blocks ( ) ) ,
98+ Mutability :: Not ,
99+ ) ;
100+ harness_body. insert_call (
101+ & self . init_contracts_hook ,
102+ & mut source,
103+ InsertPosition :: Before ,
104+ vec ! [ ] ,
105+ Place :: from ( ret_local) ,
106+ ) ;
107+ }
108+
86109 let mut arg_locals = vec ! [ ] ;
87110
88111 // For each argument of `fn_to_verify`, create a nondeterministic value of its type
0 commit comments