@@ -257,41 +257,103 @@ pub fn test_loop() {
257257 }
258258}
259259
260- // --- enum ---
260+ // --- enums ---
261261
262262enum MyEnum {
263263 Value ( i64 ) ,
264264}
265265
266- impl Drop for MyEnum {
267- fn drop ( & mut self ) {
268- println ! ( " drop MyEnum" ) ;
269- }
266+ enum MyEnum2 {
267+ Pointer ( * const i64 ) ,
270268}
271269
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 ) ;
273286 let result: * const i64 ;
274287
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)
277291
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 ( ) ;
281293
282- use_the_stack ( ) ;
294+ unsafe {
295+ let v0 = * result; // ?
296+ println ! ( " v0 = {v0} (?)" ) ;
297+ }
283298
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 ( ) ;
289306
290307 use_the_stack ( ) ;
291308
292309 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
295357 }
296358}
297359
@@ -580,3 +642,29 @@ pub fn test_lifetime_annotations() {
580642 println ! ( " v4 = {v4} (!)" ) ; // corrupt in practice
581643 }
582644}
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