@@ -35,16 +35,29 @@ pub trait TargetFinder {
35
35
fn find_all ( self , body : & MutableBody ) -> Vec < InitRelevantInstruction > ;
36
36
}
37
37
38
+ const KANI_IS_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniIsPtrInitialized" ;
39
+ const KANI_SET_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniSetPtrInitialized" ;
40
+ const KANI_IS_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniIsSliceChunkPtrInitialized" ;
41
+ const KANI_SET_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniSetSliceChunkPtrInitialized" ;
42
+ const KANI_IS_SLICE_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniIsSlicePtrInitialized" ;
43
+ const KANI_SET_SLICE_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniSetSlicePtrInitialized" ;
44
+ const KANI_IS_STR_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniIsStrPtrInitialized" ;
45
+ const KANI_SET_STR_PTR_INITIALIZED_DIAGNOSTIC : & str = "KaniSetStrPtrInitialized" ;
46
+ const KANI_COPY_INIT_STATE_DIAGNOSTIC : & str = "KaniCopyInitState" ;
47
+ const KANI_COPY_INIT_STATE_SINGLE_DIAGNOSTIC : & str = "KaniCopyInitStateSingle" ;
48
+
38
49
// Function bodies of those functions will not be instrumented as not to cause infinite recursion.
39
50
const SKIPPED_DIAGNOSTIC_ITEMS : & [ & str ] = & [
40
- "KaniIsPtrInitialized" ,
41
- "KaniSetPtrInitialized" ,
42
- "KaniIsSliceChunkPtrInitialized" ,
43
- "KaniSetSliceChunkPtrInitialized" ,
44
- "KaniIsSlicePtrInitialized" ,
45
- "KaniSetSlicePtrInitialized" ,
46
- "KaniIsStrPtrInitialized" ,
47
- "KaniSetStrPtrInitialized" ,
51
+ KANI_IS_PTR_INITIALIZED_DIAGNOSTIC ,
52
+ KANI_SET_PTR_INITIALIZED_DIAGNOSTIC ,
53
+ KANI_IS_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC ,
54
+ KANI_SET_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC ,
55
+ KANI_IS_SLICE_PTR_INITIALIZED_DIAGNOSTIC ,
56
+ KANI_SET_SLICE_PTR_INITIALIZED_DIAGNOSTIC ,
57
+ KANI_IS_STR_PTR_INITIALIZED_DIAGNOSTIC ,
58
+ KANI_SET_STR_PTR_INITIALIZED_DIAGNOSTIC ,
59
+ KANI_COPY_INIT_STATE_DIAGNOSTIC ,
60
+ KANI_COPY_INIT_STATE_SINGLE_DIAGNOSTIC ,
48
61
] ;
49
62
50
63
/// Instruments the code with checks for uninitialized memory, agnostic to the source of targets.
@@ -164,8 +177,14 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
164
177
}
165
178
MemoryInitOp :: SetSliceChunk { .. }
166
179
| MemoryInitOp :: Set { .. }
167
- | MemoryInitOp :: SetRef { .. } => self . build_set ( body, source, operation, pointee_info) ,
180
+ | MemoryInitOp :: SetRef { .. }
181
+ | MemoryInitOp :: CreateUnion { .. } => {
182
+ self . build_set ( body, source, operation, pointee_info)
183
+ }
168
184
MemoryInitOp :: Copy { .. } => self . build_copy ( body, source, operation, pointee_info) ,
185
+ MemoryInitOp :: AssignUnion { .. } => {
186
+ self . build_assign_union ( body, source, operation, pointee_info)
187
+ }
169
188
MemoryInitOp :: Unsupported { .. } | MemoryInitOp :: TriviallyUnsafe { .. } => {
170
189
unreachable ! ( )
171
190
}
@@ -196,12 +215,12 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
196
215
// pass is as an argument.
197
216
let ( diagnostic, args) = match & operation {
198
217
MemoryInitOp :: Check { .. } | MemoryInitOp :: CheckRef { .. } => {
199
- let diagnostic = "KaniIsPtrInitialized" ;
218
+ let diagnostic = KANI_IS_PTR_INITIALIZED_DIAGNOSTIC ;
200
219
let args = vec ! [ ptr_operand. clone( ) , layout_operand] ;
201
220
( diagnostic, args)
202
221
}
203
222
MemoryInitOp :: CheckSliceChunk { .. } => {
204
- let diagnostic = "KaniIsSliceChunkPtrInitialized" ;
223
+ let diagnostic = KANI_IS_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC ;
205
224
let args =
206
225
vec ! [ ptr_operand. clone( ) , layout_operand, operation. expect_count( ) ] ;
207
226
( diagnostic, args)
@@ -232,10 +251,10 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
232
251
// Since `str`` is a separate type, need to differentiate between [T] and str.
233
252
let ( slicee_ty, diagnostic) = match pointee_info. ty ( ) . kind ( ) {
234
253
TyKind :: RigidTy ( RigidTy :: Slice ( slicee_ty) ) => {
235
- ( slicee_ty, "KaniIsSlicePtrInitialized" )
254
+ ( slicee_ty, KANI_IS_SLICE_PTR_INITIALIZED_DIAGNOSTIC )
236
255
}
237
256
TyKind :: RigidTy ( RigidTy :: Str ) => {
238
- ( Ty :: unsigned_ty ( UintTy :: U8 ) , "KaniIsStrPtrInitialized" )
257
+ ( Ty :: unsigned_ty ( UintTy :: U8 ) , KANI_IS_STR_PTR_INITIALIZED_DIAGNOSTIC )
239
258
}
240
259
_ => unreachable ! ( ) ,
241
260
} ;
@@ -266,6 +285,14 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
266
285
self . inject_assert_false ( self . tcx , body, source, operation. position ( ) , reason) ;
267
286
return ;
268
287
}
288
+ PointeeLayout :: Union { .. } => {
289
+ // Here we are reading from a pointer to a union.
290
+ // TODO: we perhaps need to check that the union at least contains an intersection
291
+ // of all layouts initialized.
292
+ let reason = "Interaction between raw pointers and unions is not yet supported." ;
293
+ self . inject_assert_false ( self . tcx , body, source, operation. position ( ) , reason) ;
294
+ return ;
295
+ }
269
296
} ;
270
297
271
298
// Construct the basic block and insert it into the body.
@@ -317,7 +344,7 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
317
344
// pass is as an argument.
318
345
let ( diagnostic, args) = match & operation {
319
346
MemoryInitOp :: Set { .. } | MemoryInitOp :: SetRef { .. } => {
320
- let diagnostic = "KaniSetPtrInitialized" ;
347
+ let diagnostic = KANI_SET_PTR_INITIALIZED_DIAGNOSTIC ;
321
348
let args = vec ! [
322
349
ptr_operand,
323
350
layout_operand,
@@ -330,7 +357,7 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
330
357
( diagnostic, args)
331
358
}
332
359
MemoryInitOp :: SetSliceChunk { .. } => {
333
- let diagnostic = "KaniSetSliceChunkPtrInitialized" ;
360
+ let diagnostic = KANI_SET_SLICE_CHUNK_PTR_INITIALIZED_DIAGNOSTIC ;
334
361
let args = vec ! [
335
362
ptr_operand,
336
363
layout_operand,
@@ -369,10 +396,10 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
369
396
// Since `str`` is a separate type, need to differentiate between [T] and str.
370
397
let ( slicee_ty, diagnostic) = match pointee_info. ty ( ) . kind ( ) {
371
398
TyKind :: RigidTy ( RigidTy :: Slice ( slicee_ty) ) => {
372
- ( slicee_ty, "KaniSetSlicePtrInitialized" )
399
+ ( slicee_ty, KANI_SET_SLICE_PTR_INITIALIZED_DIAGNOSTIC )
373
400
}
374
401
TyKind :: RigidTy ( RigidTy :: Str ) => {
375
- ( Ty :: unsigned_ty ( UintTy :: U8 ) , "KaniSetStrPtrInitialized" )
402
+ ( Ty :: unsigned_ty ( UintTy :: U8 ) , KANI_SET_STR_PTR_INITIALIZED_DIAGNOSTIC )
376
403
}
377
404
_ => unreachable ! ( ) ,
378
405
} ;
@@ -409,6 +436,63 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
409
436
PointeeLayout :: TraitObject => {
410
437
unreachable ! ( "Cannot change the initialization state of a trait object directly." ) ;
411
438
}
439
+ PointeeLayout :: Union { field_layouts } => {
440
+ // Writing union data, which could be either creating a union from scratch or
441
+ // performing some pointer operations with it. If we are creating a union from
442
+ // scratch, an operation will contain a union field.
443
+
444
+ // TODO: If we don't have a union field, we are either creating a pointer to a union
445
+ // or assigning to one. In the former case, it is safe to return from this function,
446
+ // since the union must be already tracked (on creation and update). In the latter
447
+ // case, we should have been using union assignment instead. Nevertheless, this is
448
+ // currently mitigated by injecting `assert!(false)`.
449
+ let union_field = match operation. union_field ( ) {
450
+ Some ( field) => field,
451
+ None => {
452
+ let reason =
453
+ "Interaction between raw pointers and unions is not yet supported." ;
454
+ self . inject_assert_false (
455
+ self . tcx ,
456
+ body,
457
+ source,
458
+ operation. position ( ) ,
459
+ reason,
460
+ ) ;
461
+ return ;
462
+ }
463
+ } ;
464
+ let layout = & field_layouts[ union_field] ;
465
+ let layout_operand = mk_layout_operand ( body, & mut statements, source, layout) ;
466
+ let diagnostic = KANI_SET_PTR_INITIALIZED_DIAGNOSTIC ;
467
+ let args = vec ! [
468
+ ptr_operand,
469
+ layout_operand,
470
+ Operand :: Constant ( ConstOperand {
471
+ span: source. span( body. blocks( ) ) ,
472
+ user_ty: None ,
473
+ const_: MirConst :: from_bool( value) ,
474
+ } ) ,
475
+ ] ;
476
+ let set_ptr_initialized_instance = resolve_mem_init_fn (
477
+ get_mem_init_fn_def ( self . tcx , diagnostic, & mut self . mem_init_fn_cache ) ,
478
+ layout. len ( ) ,
479
+ * pointee_info. ty ( ) ,
480
+ ) ;
481
+ Terminator {
482
+ kind : TerminatorKind :: Call {
483
+ func : Operand :: Copy ( Place :: from ( body. new_local (
484
+ set_ptr_initialized_instance. ty ( ) ,
485
+ source. span ( body. blocks ( ) ) ,
486
+ Mutability :: Not ,
487
+ ) ) ) ,
488
+ args,
489
+ destination : ret_place. clone ( ) ,
490
+ target : Some ( 0 ) , // this will be overriden in add_bb
491
+ unwind : UnwindAction :: Terminate ,
492
+ } ,
493
+ span : source. span ( body. blocks ( ) ) ,
494
+ }
495
+ }
412
496
} ;
413
497
// Construct the basic block and insert it into the body.
414
498
body. insert_bb ( BasicBlock { statements, terminator } , source, operation. position ( ) ) ;
@@ -426,14 +510,19 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
426
510
local : body. new_local ( Ty :: new_tuple ( & [ ] ) , source. span ( body. blocks ( ) ) , Mutability :: Not ) ,
427
511
projection : vec ! [ ] ,
428
512
} ;
429
- let PointeeLayout :: Sized { layout } = pointee_info. layout ( ) else { unreachable ! ( ) } ;
513
+ let layout_size = pointee_info. layout ( ) . maybe_size ( ) . unwrap ( ) ;
430
514
let copy_init_state_instance = resolve_mem_init_fn (
431
- get_mem_init_fn_def ( self . tcx , "KaniCopyInitState" , & mut self . mem_init_fn_cache ) ,
432
- layout. len ( ) ,
515
+ get_mem_init_fn_def (
516
+ self . tcx ,
517
+ KANI_COPY_INIT_STATE_DIAGNOSTIC ,
518
+ & mut self . mem_init_fn_cache ,
519
+ ) ,
520
+ layout_size,
433
521
* pointee_info. ty ( ) ,
434
522
) ;
435
523
let position = operation. position ( ) ;
436
- let MemoryInitOp :: Copy { from, to, count } = operation else { unreachable ! ( ) } ;
524
+ let ( from, to) = operation. expect_copy_operands ( ) ;
525
+ let count = operation. expect_count ( ) ;
437
526
body. insert_call (
438
527
& copy_init_state_instance,
439
528
source,
@@ -443,6 +532,49 @@ impl<'a, 'tcx> UninitInstrumenter<'a, 'tcx> {
443
532
) ;
444
533
}
445
534
535
+ /// Copy memory initialization state from one union variable to another.
536
+ fn build_assign_union (
537
+ & mut self ,
538
+ body : & mut MutableBody ,
539
+ source : & mut SourceInstruction ,
540
+ operation : MemoryInitOp ,
541
+ pointee_info : PointeeInfo ,
542
+ ) {
543
+ let ret_place = Place {
544
+ local : body. new_local ( Ty :: new_tuple ( & [ ] ) , source. span ( body. blocks ( ) ) , Mutability :: Not ) ,
545
+ projection : vec ! [ ] ,
546
+ } ;
547
+ let mut statements = vec ! [ ] ;
548
+ let layout_size = pointee_info. layout ( ) . maybe_size ( ) . unwrap ( ) ;
549
+ let copy_init_state_instance = resolve_mem_init_fn (
550
+ get_mem_init_fn_def (
551
+ self . tcx ,
552
+ KANI_COPY_INIT_STATE_SINGLE_DIAGNOSTIC ,
553
+ & mut self . mem_init_fn_cache ,
554
+ ) ,
555
+ layout_size,
556
+ * pointee_info. ty ( ) ,
557
+ ) ;
558
+ let ( from, to) = operation. expect_assign_union_operands ( body, & mut statements, source) ;
559
+ let terminator = Terminator {
560
+ kind : TerminatorKind :: Call {
561
+ func : Operand :: Copy ( Place :: from ( body. new_local (
562
+ copy_init_state_instance. ty ( ) ,
563
+ source. span ( body. blocks ( ) ) ,
564
+ Mutability :: Not ,
565
+ ) ) ) ,
566
+ args : vec ! [ from, to] ,
567
+ destination : ret_place. clone ( ) ,
568
+ target : Some ( 0 ) , // this will be overriden in add_bb
569
+ unwind : UnwindAction :: Terminate ,
570
+ } ,
571
+ span : source. span ( body. blocks ( ) ) ,
572
+ } ;
573
+
574
+ // Construct the basic block and insert it into the body.
575
+ body. insert_bb ( BasicBlock { statements, terminator } , source, operation. position ( ) ) ;
576
+ }
577
+
446
578
fn inject_assert_false (
447
579
& self ,
448
580
tcx : TyCtxt ,
0 commit comments