lifetime_extender/
lib.rs

1#![forbid(unsafe_code)] // WTF?
2#![cfg_attr(doc, feature(doc_auto_cfg))]
3//! # A Very unsafe lifetime extender with only safe Rust
4//! This crate is published for a severe bug that allow user write safe code to extend the lifetime
5//! of any object, which is unacceptable since such behavior may easily leads to UAF, double free
6//! and many UB. This crate should NOT used in the real life, since it relies on a BUG, not a
7//! feature.
8//!
9//! Here, 2 functions are provided, one is `extend`, which could extend any borrow's lifetime to
10//! `'static` (should be the longest lifetime), and another is the mutable version `extend_mut`,
11//! which could extend the mutable borrows. The former one may easily leads to UAF, and the second
12//! one
13//!
14//! The crate uses `!#[forbid(unsafe_code)]` to ensure only safe rust is used.
15//!
16//! All the functions are ZCA, which could be directly optimized out.
17//!
18//! By default, all functions are hidden since you should use none of them. You could test them
19//! with the related feature (in case some of them is fixed and others have not.)
20//! Using the most dangerous `i-can-do-whatever-the-fxxk-i-want` feature gate would enable all
21//! the features.
22/// extend the current lifetime to `'static`.
23#[inline(always)]
24#[cfg(any(feature = "test-borrow", doc))]
25pub fn extend<'a, T>(input: &'a T) -> &'static T {
26    struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]);
27    let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
28    n(input).0
29}
30/// extend the current mutable borrow's lifetime to `'static`
31#[inline(always)]
32#[cfg(any(feature = "test-borrow-mut", doc))]
33pub fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
34    struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]);
35    let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
36    n(input).0
37}
38/// a similar function from fake-static, doing the same things as [`extend`]
39#[inline(always)]
40#[cfg(any(feature = "test-fake-static-borrow", doc))]
41pub fn make_static<'a, T>(input: &'a T) -> &'static T {
42    fn helper<'a, T>(_: [&'static &'a (); 0], v: &'a T) -> &'static T {
43        v
44    }
45    let f: fn([&'static &(); 0], &T) -> &'static T = helper;
46    f([], input) // we need not to create a &'a&'b unit directly.
47}
48/// a similar function from fake-static, doing the same things as [`extend_mut`]
49#[inline(always)]
50#[cfg(any(feature = "test-fake-static-borrow-mut", doc))]
51pub fn make_static_mut<'a, T>(input: &'a mut T) -> &'static mut T {
52    fn helper_mut<'a, T>(_: [&'static &'a (); 0], v: &'a mut T) -> &'static mut T {
53        v
54    }
55    let f: fn([&'static &'static (); 0], &'a mut T) -> &'static mut T = helper_mut;
56    // let f: fn([&'static&();0], &mut T) -> &'static mut T = helper_mut; // it also works
57    f([], input)
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    #[test]
64    #[should_panic]
65    #[cfg(feature = "test-borrow-mut")]
66    fn it_panics() {
67        let mut a = vec![1, 2, 3, 4, 5, 6, 7, 8];
68        let b = extend_mut(&mut a);
69        drop(a);
70        //b.push(0);// double free is not panic!
71        panic!("{b:?} is still readable!");
72    }
73    #[test]
74    #[should_panic]
75    #[cfg(feature = "test-borrow")]
76    fn uaf() {
77        let a = vec![1, 2, 3, 4];
78        let b = extend(&a);
79        drop(a);
80        assert_eq!(b, &[1, 2, 3, 4]);
81    }
82    #[test]
83    #[should_panic]
84    #[cfg(feature = "test-fake-static-borrow-mut")]
85    fn it_panics_2() {
86        let mut a = vec![1, 2, 3, 4, 5, 6, 7, 8];
87        let b = make_static_mut(&mut a);
88        drop(a);
89        //b.push(0);// double free is not panic!
90        panic!("{b:?} is still readable!");
91    }
92    #[test]
93    #[should_panic]
94    #[cfg(feature = "test-fake-static-borrow")]
95    fn uaf_2() {
96        let a = vec![1, 2, 3, 4];
97        let b = make_static(&a);
98        drop(a);
99        assert_eq!(b, &[1, 2, 3, 4]);
100    }
101}