@@ -29,8 +29,17 @@ mod uninit_visitor;
2929pub use ty_layout:: { PointeeInfo , PointeeLayout } ;
3030use uninit_visitor:: { CheckUninitVisitor , InitRelevantInstruction , MemoryInitOp } ;
3131
32- const SKIPPED_DIAGNOSTIC_ITEMS : & [ & str ] =
33- & [ "KaniIsUnitPtrInitialized" , "KaniSetUnitPtrInitialized" ] ;
32+ // Function bodies of those functions will not be instrumented as not to cause infinite recursion.
33+ const SKIPPED_DIAGNOSTIC_ITEMS : & [ & str ] = & [
34+ "KaniIsPtrInitialized" ,
35+ "KaniSetPtrInitialized" ,
36+ "KaniIsSliceChunkPtrInitialized" ,
37+ "KaniSetSliceChunkPtrInitialized" ,
38+ "KaniIsSlicePtrInitialized" ,
39+ "KaniSetSlicePtrInitialized" ,
40+ "KaniIsStrPtrInitialized" ,
41+ "KaniSetStrPtrInitialized" ,
42+ ] ;
3443
3544/// Instrument the code with checks for uninitialized memory.
3645#[ derive( Debug ) ]
@@ -59,8 +68,8 @@ impl TransformPass for UninitPass {
5968 fn transform ( & mut self , tcx : TyCtxt , body : Body , instance : Instance ) -> ( bool , Body ) {
6069 trace ! ( function=?instance. name( ) , "transform" ) ;
6170
62- // Need to break infinite recursion when shadow memory checks are inserted,
63- // so the internal function responsible for shadow memory checks are skipped.
71+ // Need to break infinite recursion when memory initialization checks are inserted, so the
72+ // internal functions responsible for memory initialization are skipped.
6473 if tcx
6574 . get_diagnostic_name ( rustc_internal:: internal ( tcx, instance. def . def_id ( ) ) )
6675 . map ( |diagnostic_name| {
@@ -74,6 +83,11 @@ impl TransformPass for UninitPass {
7483 let mut new_body = MutableBody :: from ( body) ;
7584 let orig_len = new_body. blocks ( ) . len ( ) ;
7685
86+ // Inject a call to set-up memory initialization state if the function is a harness.
87+ if is_harness ( instance, tcx) {
88+ inject_memory_init_setup ( & mut new_body, tcx, & mut self . mem_init_fn_cache ) ;
89+ }
90+
7791 // Set of basic block indices for which analyzing first statement should be skipped.
7892 //
7993 // This is necessary because some checks are inserted before the source instruction, which, in
@@ -159,10 +173,12 @@ impl UninitPass {
159173 } ;
160174
161175 match operation {
162- MemoryInitOp :: Check { .. } => {
176+ MemoryInitOp :: CheckSliceChunk { .. } | MemoryInitOp :: Check { .. } => {
163177 self . build_get_and_check ( tcx, body, source, operation, pointee_ty_info, skip_first)
164178 }
165- MemoryInitOp :: Set { .. } | MemoryInitOp :: SetRef { .. } => {
179+ MemoryInitOp :: SetSliceChunk { .. }
180+ | MemoryInitOp :: Set { .. }
181+ | MemoryInitOp :: SetRef { .. } => {
166182 self . build_set ( tcx, body, source, operation, pointee_ty_info, skip_first)
167183 }
168184 MemoryInitOp :: Unsupported { .. } => {
@@ -171,8 +187,8 @@ impl UninitPass {
171187 }
172188 }
173189
174- /// Inject a load from shadow memory tracking memory initialization and an assertion that all
175- /// non-padding bytes are initialized.
190+ /// Inject a load from memory initialization state and an assertion that all non-padding bytes
191+ /// are initialized.
176192 fn build_get_and_check (
177193 & mut self ,
178194 tcx : TyCtxt ,
@@ -189,18 +205,34 @@ impl UninitPass {
189205 let ptr_operand = operation. mk_operand ( body, source) ;
190206 match pointee_info. layout ( ) {
191207 PointeeLayout :: Sized { layout } => {
208+ let layout_operand = mk_layout_operand ( body, source, operation. position ( ) , & layout) ;
209+ // Depending on whether accessing the known number of elements in the slice, need to
210+ // pass is as an argument.
211+ let ( diagnostic, args) = match & operation {
212+ MemoryInitOp :: Check { .. } => {
213+ let diagnostic = "KaniIsPtrInitialized" ;
214+ let args = vec ! [ ptr_operand. clone( ) , layout_operand] ;
215+ ( diagnostic, args)
216+ }
217+ MemoryInitOp :: CheckSliceChunk { .. } => {
218+ let diagnostic = "KaniIsSliceChunkPtrInitialized" ;
219+ let args =
220+ vec ! [ ptr_operand. clone( ) , layout_operand, operation. expect_count( ) ] ;
221+ ( diagnostic, args)
222+ }
223+ _ => unreachable ! ( ) ,
224+ } ;
192225 let is_ptr_initialized_instance = resolve_mem_init_fn (
193- get_mem_init_fn_def ( tcx, "KaniIsPtrInitialized" , & mut self . mem_init_fn_cache ) ,
226+ get_mem_init_fn_def ( tcx, diagnostic , & mut self . mem_init_fn_cache ) ,
194227 layout. len ( ) ,
195228 * pointee_info. ty ( ) ,
196229 ) ;
197- let layout_operand = mk_layout_operand ( body, source, operation. position ( ) , & layout) ;
198230 collect_skipped ( & operation, body, skip_first) ;
199231 body. add_call (
200232 & is_ptr_initialized_instance,
201233 source,
202234 operation. position ( ) ,
203- vec ! [ ptr_operand . clone ( ) , layout_operand , operation . expect_count ( ) ] ,
235+ args ,
204236 ret_place. clone ( ) ,
205237 ) ;
206238 }
@@ -252,8 +284,8 @@ impl UninitPass {
252284 )
253285 }
254286
255- /// Inject a store into shadow memory tracking memory initialization to initialize or
256- /// deinitialize all non-padding bytes.
287+ /// Inject a store into memory initialization state to initialize or deinitialize all
288+ /// non-padding bytes.
257289 fn build_set (
258290 & mut self ,
259291 tcx : TyCtxt ,
@@ -272,27 +304,50 @@ impl UninitPass {
272304
273305 match pointee_info. layout ( ) {
274306 PointeeLayout :: Sized { layout } => {
307+ let layout_operand = mk_layout_operand ( body, source, operation. position ( ) , & layout) ;
308+ // Depending on whether writing to the known number of elements in the slice, need to
309+ // pass is as an argument.
310+ let ( diagnostic, args) = match & operation {
311+ MemoryInitOp :: Set { .. } | MemoryInitOp :: SetRef { .. } => {
312+ let diagnostic = "KaniSetPtrInitialized" ;
313+ let args = vec ! [
314+ ptr_operand,
315+ layout_operand,
316+ Operand :: Constant ( ConstOperand {
317+ span: source. span( body. blocks( ) ) ,
318+ user_ty: None ,
319+ const_: MirConst :: from_bool( value) ,
320+ } ) ,
321+ ] ;
322+ ( diagnostic, args)
323+ }
324+ MemoryInitOp :: SetSliceChunk { .. } => {
325+ let diagnostic = "KaniSetSliceChunkPtrInitialized" ;
326+ let args = vec ! [
327+ ptr_operand,
328+ layout_operand,
329+ operation. expect_count( ) ,
330+ Operand :: Constant ( ConstOperand {
331+ span: source. span( body. blocks( ) ) ,
332+ user_ty: None ,
333+ const_: MirConst :: from_bool( value) ,
334+ } ) ,
335+ ] ;
336+ ( diagnostic, args)
337+ }
338+ _ => unreachable ! ( ) ,
339+ } ;
275340 let set_ptr_initialized_instance = resolve_mem_init_fn (
276- get_mem_init_fn_def ( tcx, "KaniSetPtrInitialized" , & mut self . mem_init_fn_cache ) ,
341+ get_mem_init_fn_def ( tcx, diagnostic , & mut self . mem_init_fn_cache ) ,
277342 layout. len ( ) ,
278343 * pointee_info. ty ( ) ,
279344 ) ;
280- let layout_operand = mk_layout_operand ( body, source, operation. position ( ) , & layout) ;
281345 collect_skipped ( & operation, body, skip_first) ;
282346 body. add_call (
283347 & set_ptr_initialized_instance,
284348 source,
285349 operation. position ( ) ,
286- vec ! [
287- ptr_operand,
288- layout_operand,
289- operation. expect_count( ) ,
290- Operand :: Constant ( ConstOperand {
291- span: source. span( body. blocks( ) ) ,
292- user_ty: None ,
293- const_: MirConst :: from_bool( value) ,
294- } ) ,
295- ] ,
350+ args,
296351 ret_place,
297352 ) ;
298353 }
@@ -426,3 +481,59 @@ pub fn resolve_mem_init_fn(fn_def: FnDef, layout_size: usize, associated_type: T
426481 )
427482 . unwrap ( )
428483}
484+
485+ /// Checks if the instance is a harness -- an entry point of Kani analysis.
486+ fn is_harness ( instance : Instance , tcx : TyCtxt ) -> bool {
487+ let harness_identifiers = [
488+ vec ! [
489+ rustc_span:: symbol:: Symbol :: intern( "kanitool" ) ,
490+ rustc_span:: symbol:: Symbol :: intern( "proof_for_contract" ) ,
491+ ] ,
492+ vec ! [
493+ rustc_span:: symbol:: Symbol :: intern( "kanitool" ) ,
494+ rustc_span:: symbol:: Symbol :: intern( "proof" ) ,
495+ ] ,
496+ ] ;
497+ harness_identifiers. iter ( ) . any ( |attr_path| {
498+ tcx. has_attrs_with_path ( rustc_internal:: internal ( tcx, instance. def . def_id ( ) ) , attr_path)
499+ } )
500+ }
501+
502+ /// Inject an initial call to set-up memory initialization tracking.
503+ fn inject_memory_init_setup (
504+ new_body : & mut MutableBody ,
505+ tcx : TyCtxt ,
506+ mem_init_fn_cache : & mut HashMap < & ' static str , FnDef > ,
507+ ) {
508+ // First statement or terminator in the harness.
509+ let mut source = if !new_body. blocks ( ) [ 0 ] . statements . is_empty ( ) {
510+ SourceInstruction :: Statement { idx : 0 , bb : 0 }
511+ } else {
512+ SourceInstruction :: Terminator { bb : 0 }
513+ } ;
514+
515+ // Dummy return place.
516+ let ret_place = Place {
517+ local : new_body. new_local (
518+ Ty :: new_tuple ( & [ ] ) ,
519+ source. span ( new_body. blocks ( ) ) ,
520+ Mutability :: Not ,
521+ ) ,
522+ projection : vec ! [ ] ,
523+ } ;
524+
525+ // Resolve the instance and inject a call to set-up the memory initialization state.
526+ let memory_initialization_init = Instance :: resolve (
527+ get_mem_init_fn_def ( tcx, "KaniInitializeMemoryInitializationState" , mem_init_fn_cache) ,
528+ & GenericArgs ( vec ! [ ] ) ,
529+ )
530+ . unwrap ( ) ;
531+
532+ new_body. add_call (
533+ & memory_initialization_init,
534+ & mut source,
535+ InsertPosition :: Before ,
536+ vec ! [ ] ,
537+ ret_place,
538+ ) ;
539+ }
0 commit comments