forked from rust-lang/rust
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of rust-lang#127435 - GrigorenkoPV:tests-for-112905, r=cjg…
…illot Add tests for rust-lang#112905 This is a part of rust-lang#105107. Adds the tests from the OP in rust-lang#112905.
- Loading branch information
Showing
2 changed files
with
92 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
//@ known-bug: #112905 | ||
//@ check-pass | ||
|
||
// Classified as an issue with implied bounds: | ||
// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 | ||
|
||
/// Note: this is sound! It's the "type witness" pattern (here, lt witness). | ||
mod some_lib { | ||
use super::T; | ||
|
||
/// Invariant in `'a` and `'b` for soundness. | ||
pub struct LtEq<'a, 'b>(::std::marker::PhantomData<*mut Self>); | ||
|
||
impl<'a, 'b> LtEq<'a, 'b> { | ||
pub fn new() -> LtEq<'a, 'a> { | ||
LtEq(<_>::default()) | ||
} | ||
|
||
pub fn eq(&self) -> impl 'static + Fn(T<'a>) -> T<'b> { | ||
|a| unsafe { ::std::mem::transmute::<T<'a>, T<'b>>(a) } | ||
} | ||
} | ||
} | ||
|
||
use some_lib::LtEq; | ||
use std::{any::Any, cell::Cell}; | ||
|
||
/// Feel free to choose whatever you want, here. | ||
type T<'lt> = Cell<&'lt str>; | ||
|
||
fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { | ||
let f = LtEq::<'a, 'a>::new().eq(); | ||
let any = Box::new(f) as Box<dyn Any>; | ||
|
||
let new_f = None.map(LtEq::<'a, 'b>::eq); | ||
|
||
fn downcast_a_to_type_of_new_f<F: 'static>(any: Box<dyn Any>, _: Option<F>) -> F { | ||
*any.downcast().unwrap_or_else(|_| unreachable!()) | ||
} | ||
|
||
let f = downcast_a_to_type_of_new_f(any, new_f); | ||
|
||
f(a) | ||
} | ||
|
||
fn main() { | ||
let r: T<'static> = { | ||
let local = String::from("…"); | ||
let a: T<'_> = Cell::new(&local[..]); | ||
exploit(a) | ||
}; | ||
dbg!(r.get()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
//@ known-bug: #112905 | ||
//@ check-pass | ||
|
||
// Classified as an issue with implied bounds: | ||
// https://github.com/rust-lang/rust/issues/112905#issuecomment-1757847998 | ||
|
||
#![forbid(unsafe_code)] // No `unsafe!` | ||
#![feature(type_alias_impl_trait)] | ||
|
||
use std::any::Any; | ||
|
||
/// Anything covariant will do, for this demo. | ||
type T<'lt> = &'lt str; | ||
|
||
type F<'a, 'b> = impl 'static + Fn(T<'a>) -> T<'b>; | ||
|
||
fn helper<'a, 'b>(_: [&'b &'a (); 0]) -> F<'a, 'b> { | ||
|x: T<'a>| -> T<'b> { x } // this should *not* be `: 'static` | ||
} | ||
|
||
fn exploit<'a, 'b>(a: T<'a>) -> T<'b> { | ||
let f: F<'a, 'a> = helper([]); | ||
let any = Box::new(f) as Box<dyn Any>; | ||
|
||
let f: F<'a, 'static> = *any.downcast().unwrap_or_else(|_| unreachable!()); | ||
|
||
f(a) | ||
} | ||
|
||
fn main() { | ||
let r: T<'static> = { | ||
let local = String::from("..."); | ||
exploit(&local) | ||
}; | ||
// Since `r` now dangles, we can easily make the use-after-free | ||
// point to newly allocated memory! | ||
let _unrelated = String::from("UAF"); | ||
dbg!(r); // may print `UAF`! Run with `miri` to see the UB. | ||
} |