Skip to content

Commit

Permalink
Auto merge of rust-lang#127435 - GrigorenkoPV:tests-for-112905, r=cjg…
Browse files Browse the repository at this point in the history
…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
bors committed Jul 13, 2024
2 parents c1e3f03 + 32294aa commit 25acbbd
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
53 changes: 53 additions & 0 deletions tests/ui/implied-bounds/dyn-erasure-no-tait.rs
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());
}
39 changes: 39 additions & 0 deletions tests/ui/implied-bounds/dyn-erasure-tait.rs
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.
}

0 comments on commit 25acbbd

Please sign in to comment.