@@ -257,41 +257,103 @@ pub fn test_loop() {
257
257
}
258
258
}
259
259
260
- // --- enum ---
260
+ // --- enums ---
261
261
262
262
enum MyEnum {
263
263
Value ( i64 ) ,
264
264
}
265
265
266
- impl Drop for MyEnum {
267
- fn drop ( & mut self ) {
268
- println ! ( " drop MyEnum" ) ;
269
- }
266
+ enum MyEnum2 {
267
+ Pointer ( * const i64 ) ,
270
268
}
271
269
272
- pub fn test_enum ( ) {
270
+ pub fn get_pointer_to_enum ( ) -> * const MyEnum {
271
+ let e1 = MyEnum :: Value ( 1 ) ;
272
+ let result: * const MyEnum = & e1; // $ MISSING: Source[rust/access-after-lifetime-ended]=e1
273
+
274
+ result
275
+ } // (e1 goes out of scope, so result is dangling)
276
+
277
+ pub fn get_pointer_in_enum ( ) -> MyEnum2 {
278
+ let v2 = 2 ;
279
+ let e2 = MyEnum2 :: Pointer ( & v2) ; // $ MISSING: Source[rust/access-after-lifetime-ended]=v2
280
+
281
+ e2
282
+ } // (v2 goes out of scope, so the contained pointer is dangling)
283
+
284
+ pub fn get_pointer_from_enum ( ) -> * const i64 {
285
+ let e3 = MyEnum :: Value ( 3 ) ;
273
286
let result: * const i64 ;
274
287
275
- {
276
- let e1 = MyEnum :: Value ( 1 ) ;
288
+ result = match e3 {
289
+ MyEnum :: Value ( x) => { & x } // $ MISSING: Source[rust/access-after-lifetime-ended]=match_x
290
+ } ; // (x goes out of scope, so result is possibly dangling already)
277
291
278
- result = match e1 {
279
- MyEnum :: Value ( x) => { & x }
280
- } ; // (x goes out of scope, so result is dangling, I think; seen in real world code)
292
+ use_the_stack ( ) ;
281
293
282
- use_the_stack ( ) ;
294
+ unsafe {
295
+ let v0 = * result; // ?
296
+ println ! ( " v0 = {v0} (?)" ) ;
297
+ }
283
298
284
- unsafe {
285
- let v1 = * result; // $ MISSING: Alert
286
- println ! ( " v1 = {v1}" ) ;
287
- }
288
- } // (e1 goes out of scope, so result is definitely dangling now)
299
+ result
300
+ } // (e3 goes out of scope, so result is definitely dangling now)
301
+
302
+ pub fn test_enums ( ) {
303
+ let e1 = get_pointer_to_enum ( ) ;
304
+ let e2 = get_pointer_in_enum ( ) ;
305
+ let result = get_pointer_from_enum ( ) ;
289
306
290
307
use_the_stack ( ) ;
291
308
292
309
unsafe {
293
- let v2 = * result; // $ MISSING: Alert
294
- println ! ( " v2 = {v2}" ) ; // dropped in practice
310
+ if let MyEnum :: Value ( v1) = * e1 { // $ MISSING: Alert[rust/access-after-lifetime-ended]=e1
311
+ println ! ( " v1 = {v1} (!)" ) ; // corrupt in practice
312
+ }
313
+ if let MyEnum2 :: Pointer ( p2) = e2 {
314
+ let v2 = unsafe { * p2 } ; // $ MISSING: Alert[rust/access-after-lifetime-ended]=v2
315
+ println ! ( " v2 = {v2} (!)" ) ; // corrupt in practice
316
+ }
317
+ let v3 = * result; // $ MISSING: Alert[rust/access-after-lifetime-ended]=match_x
318
+ println ! ( " v3 = {v3} (!)" ) ; // corrupt in practice
319
+ }
320
+ }
321
+
322
+ // --- recursive enum ---
323
+
324
+ enum RecursiveEnum {
325
+ Wrapper ( Box < RecursiveEnum > ) ,
326
+ Pointer ( * const i64 ) ,
327
+ }
328
+
329
+ pub fn get_recursive_enum ( ) -> Box < RecursiveEnum > {
330
+ let v1 = 1 ;
331
+ let enum1 = RecursiveEnum :: Wrapper ( Box :: new ( RecursiveEnum :: Pointer ( & v1) ) ) ; // Source[rust/access-after-lifetime-ended]=v1
332
+ let mut ref1 = & enum1;
333
+
334
+ while let RecursiveEnum :: Wrapper ( inner) = ref1 {
335
+ println ! ( " wrapper" ) ;
336
+ ref1 = & inner;
337
+ }
338
+ if let RecursiveEnum :: Pointer ( ptr) = ref1 {
339
+ let v2: i64 = unsafe { * * ptr } ; // GOOD
340
+ println ! ( " v2 = {v2}" ) ;
341
+ }
342
+
343
+ return Box :: new ( enum1) ;
344
+ } // (v1 goes out of scope, thus the contained pointer is dangling)
345
+
346
+ pub fn test_recursive_enums ( ) {
347
+ let enum1 = * get_recursive_enum ( ) ;
348
+ let mut ref1 = & enum1;
349
+
350
+ while let RecursiveEnum :: Wrapper ( inner) = ref1 {
351
+ println ! ( " wrapper" ) ;
352
+ ref1 = & inner;
353
+ }
354
+ if let RecursiveEnum :: Pointer ( ptr) = ref1 {
355
+ let v3: i64 = unsafe { * * ptr } ; // Alert[rust/access-after-lifetime-ended]=v1
356
+ println ! ( " v3 = {v3} (!)" ) ; // corrupt in practice
295
357
}
296
358
}
297
359
@@ -580,3 +642,29 @@ pub fn test_lifetime_annotations() {
580
642
println ! ( " v4 = {v4} (!)" ) ; // corrupt in practice
581
643
}
582
644
}
645
+
646
+ // --- implicit dereferences ---
647
+
648
+ pub fn test_implicit_derefs ( ) {
649
+ let ref1;
650
+ {
651
+ let str2;
652
+ {
653
+ let str1 = "bar" ;
654
+ str2 = "foo" . to_string ( ) + & str1; // $ MISSING: Source[rust/access-after-lifetime-ended]=str1
655
+ ref1 = & raw const str2; // $ MISSING: Source[rust/access-after-lifetime-ended]=str2
656
+ } // (str1 goes out of scope, but it's been copied into str2)
657
+
658
+ unsafe {
659
+ let v1 = & * ref1; // GOOD
660
+ println ! ( " v1 = {v1}" ) ;
661
+ }
662
+ } // (str2 goes out of scope, thus ref1 is dangling)
663
+
664
+ use_the_stack ( ) ;
665
+
666
+ unsafe {
667
+ let v2 = & * ref1; // $ MISSING: Alert[rust/access-after-lifetime-ended]=str2
668
+ println ! ( " v2 = {v2} (!)" ) ; // corrupt in practice
669
+ }
670
+ }
0 commit comments