@@ -441,3 +441,93 @@ pub fn test_rc() {
441
441
// note: simialar things are likely possible with Ref, RefMut, RefCell,
442
442
// Vec and others.
443
443
}
444
+
445
+ // --- closures ---
446
+
447
+ fn get_closure ( p3 : * const i64 , p4 : * const i64 ) -> impl FnOnce ( ) {
448
+ let my_local1: i64 = 1 ;
449
+ let my_local2: i64 = 2 ;
450
+ let p1: * const i64 = & my_local1;
451
+
452
+ return move || { // captures `my_local2`, `p1`, `p3`, `p4` by value (due to `move`)
453
+ let p2: * const i64 = & my_local2;
454
+
455
+ unsafe {
456
+ let v1 = * p1; // $ MISSING: Alert
457
+ let v2 = * p2; // GOOD
458
+ let v3 = * p3; // GOOD
459
+ let v4 = * p4; // $ MISSING: Alert
460
+ println ! ( " v1 = {v1} (!)" ) ; // corrupt in practice
461
+ println ! ( " v2 = {v2}" ) ;
462
+ println ! ( " v3 = {v3}" ) ;
463
+ println ! ( " v4 = {v4} (!)" ) ;
464
+ }
465
+ } ;
466
+ } // (`my_local1` goes out of scope, thus `p1` is dangling)
467
+
468
+ fn with_closure ( ptr : * const i64 , closure : fn ( * const i64 , * const i64 ) ) {
469
+ let my_local5: i64 = 5 ;
470
+
471
+ closure ( ptr,
472
+ & my_local5) ;
473
+ }
474
+
475
+ pub fn test_closures ( ) {
476
+ let closure;
477
+ let my_local3: i64 = 3 ;
478
+ {
479
+ let my_local4: i64 = 4 ;
480
+ closure = get_closure ( & my_local3,
481
+ & my_local4) ;
482
+ } // (`my_local4` goes out of scope, so `p4` is dangling)
483
+
484
+ use_the_stack ( ) ;
485
+
486
+ closure ( ) ;
487
+
488
+ with_closure ( & my_local3, |p1, p2| {
489
+ unsafe {
490
+ let v5 = * p1; // GOOD
491
+ let v6 = * p2; // GOOD
492
+ println ! ( " v5 = {v5}" ) ;
493
+ println ! ( " v6 = {v6}" ) ;
494
+ }
495
+ } ) ;
496
+ }
497
+
498
+ // --- async ---
499
+
500
+ fn get_async_closure ( p3 : * const i64 , p4 : * const i64 ) -> impl std:: future:: Future < Output = ( ) > {
501
+ let my_local1: i64 = 1 ;
502
+ let my_local2: i64 = 2 ;
503
+ let p1: * const i64 = & my_local1;
504
+
505
+ return async move { // captures `my_local2`, `p1`, `p3`, `p4` by value (due to `move`)
506
+ let p2: * const i64 = & my_local2;
507
+
508
+ unsafe {
509
+ let v1 = * p1; // $ MISSING: Alert
510
+ let v2 = * p2; // GOOD
511
+ let v3 = * p3; // GOOD
512
+ let v4 = * p4; // $ MISSING: Alert
513
+ println ! ( " v1 = {v1} (!)" ) ; // corrupt in practice
514
+ println ! ( " v2 = {v2}" ) ;
515
+ println ! ( " v3 = {v3}" ) ;
516
+ println ! ( " v4 = {v4} (!)" ) ;
517
+ }
518
+ } ;
519
+ } // (`my_local1` goes out of scope, thus `p1` is dangling)
520
+
521
+ pub fn test_async ( ) {
522
+ let async_closure;
523
+ let my_local3: i64 = 3 ;
524
+ {
525
+ let my_local4: i64 = 4 ;
526
+ async_closure = get_async_closure ( & my_local3,
527
+ & my_local4) ;
528
+ } // (`my_local4` goes out of scope, so `p4` is dangling)
529
+
530
+ use_the_stack ( ) ;
531
+
532
+ futures:: executor:: block_on ( async_closure) ;
533
+ }
0 commit comments