A new Bug for the famous #25860 issue

I had simplified the recent found bug as

fn extend<T>(input: &T) -> &'static T {
    struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b ();0]);
    let n:Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>>=Box::new(|x| Bounded(x, []));
    n(input).0
}
fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T {
    struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b ();0]);
    let mut n:Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>>=Box::new(|x| Bounded(x, []));
    n(input).0
}

It could be found easily that, we need constrain 'a outlives 'b, since when we wrote Bounded<'a: 'b, 'b, T>, the compiler returns an error, said that '1 must outlives 'static.

It seems that, the lifetime is inverted here: The constrain 'a:'b is bypassed by 'b:'a.

I suspect it is a compiler bug, but have no idea how to fix it.

I have publish a crate for such feature, allowing duplicating any borrows (even &mut). You could test the functions in that crate

1 Like

Is publishing a crate the right thing to do here? Years ago someone published a "fake-static" crate, necessitating a security advisory.

This is definitely a bug but is it issue 25860? I thought that had to do with the inability to write for<'a where 'a: 'b>.

2 Likes

The crate is released for debug purpose, let people know and test whether the bug has been eliminated or still exists.

As for whether it is for issue 25860.. I have no idea since my code is trying to simplify the most recent implementation of that issue.


What's more, my simplification shows that, 'b in the fake-static crate is unnecessary. 'a: 'static might be inferred from the &'static &'a pattern directly, and then we create a fake data that bypass the &'static &'a check, which leads to the final error.

pub fn make_static<'a, T>(input: &'a T) -> &'static T {
    fn helper<'a, T>(_: [&'static&'a();0], v: &'a T) -> &'static T { v }
    let f: fn([&'static&();0], &T) -> &'static T = helper;
    f([], input) // we need not to create a &'a&'b unit directly.
}
pub fn make_static_mut<'a, T>(input: &'a mut T) -> &'static mut T {
    fn helper_mut<'a, T>(_: [&'static&'a();0], v: &'a mut T) -> &'static mut T { v }
    let f: fn([&'static&'static();0], &'a mut T) -> &'static mut T = helper_mut;
    // let f: fn([&'static&();0], &mut T) -> &'static mut T = helper_mut; // it also works
    f([], input)
}

It is worth mention that, make_static_mut just duplicate the input. After call make_static_mut, both the input and the return value are useable, which seems to be a disaster.

I don't think this needs a crate, but even then at least fake-static has a compile error switch in release mode:

#[cfg(not(debug_assertions))]
compile_error!("Don't deploy this shit to production you madman");
5 Likes

Thanks for your suggestion, I added several feature gates.