Skip to main content

lifetime_extender/
lib.rs

1#![forbid(unsafe_code)] // WTF?
2#![cfg_attr(doc, feature(doc_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//! By default, all functions are hidden since you should use none of them. You could test them
17//! with the related feature (in case some of them is fixed and others have not.)
18//! Using the most dangerous `i-can-do-whatever-the-fxxk-i-want` feature gate would enable all
19//! the checked features that are still valid in Rust 1.9x.
20/// extend the current lifetime to `'static`.
21#[inline(always)]
22#[cfg(any(feature = "test-borrow", doc))]
23pub fn extend<'a, T>(input: &'a T) -> &'static T {
24    struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]);
25    let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
26    n(input).0
27}
28/// extend the current mutable borrow's lifetime to `'static`
29#[inline(always)]
30#[cfg(any(feature = "test-borrow-mut", doc))]
31pub fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
32    struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]);
33    let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, []));
34    n(input).0
35}
36/// a similar function from fake-static, doing the same things as [`extend`]
37#[inline(always)]
38#[cfg(any(feature = "test-fake-static-borrow", doc))]
39pub fn make_static<T>(input: &'_ T) -> &'static T {
40    fn helper<'a, T>(_: [(&'static &'a T, &'static T); 0], v: &'a T) -> &'static T {
41        v
42    }
43    let f: fn([(&'static &T, &'static T); 0], &T) -> &'static T = helper;
44    f([], input) // we need not to create a &'a&'b unit directly.
45}
46/// a similar function from fake-static, doing the same things as [`extend_mut`]
47#[inline(always)]
48#[cfg(any(feature = "test-fake-static-borrow-mut", doc))]
49pub fn make_static_mut<T>(input: &'_ mut T) -> &'static mut T {
50    fn helper_mut<'a, T>(_: [(&'static &'a T, &'static T); 0], v: &'a mut T) -> &'static mut T {
51        v
52    }
53    // let f: fn([&'static &'static (); 0], &'a mut T) -> &'static mut T = helper_mut; // cannot compile
54    let f: fn([(&'static &'_ T, &'static T); 0], &'_ mut T) -> &'static mut T = helper_mut; // it also works
55    f([], input)
56}
57
58#[cfg(test)]
59mod tests {
60    #[cfg(any(
61        feature = "test-borrow-mut",
62        feature = "test-borrow",
63        feature = "test-fake-static-borrow-mut",
64        feature = "test-fake-static-borrow"
65    ))]
66    use super::*;
67    #[test]
68    #[should_panic]
69    #[cfg(feature = "test-borrow-mut")]
70    fn it_panics() {
71        let mut a = vec![1, 2, 3, 4, 5, 6, 7, 8];
72        let b = extend_mut(&mut a);
73        drop(a);
74        //b.push(0);// double free is not panic!
75        panic!("{b:?} is still readable!");
76    }
77    #[test]
78    #[should_panic]
79    #[cfg(feature = "test-borrow")]
80    fn uaf() {
81        let a = vec![1, 2, 3, 4];
82        let b = extend(&a);
83        drop(a);
84        assert_eq!(b, &[1, 2, 3, 4]);
85    }
86    #[test]
87    #[should_panic]
88    #[cfg(feature = "test-fake-static-borrow-mut")]
89    fn it_panics_2() {
90        let mut a = vec![1, 2, 3, 4, 5, 6, 7, 8];
91        let b = make_static_mut(&mut a);
92        drop(a);
93        //b.push(0);// double free is not panic!
94        panic!("{b:?} is still readable!");
95    }
96    #[test]
97    #[should_panic]
98    #[cfg(feature = "test-fake-static-borrow")]
99    fn uaf_2() {
100        let a = vec![1, 2, 3, 4];
101        let b = make_static(&a);
102        drop(a);
103        assert_eq!(b, &[1, 2, 3, 4]);
104    }
105}