Skip to content

Commit f20e0c7

Browse files
committed
Forbid object lifetime changing pointer casts
1 parent 41a79f1 commit f20e0c7

File tree

8 files changed

+106
-12
lines changed

8 files changed

+106
-12
lines changed

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,21 +1467,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14671467
//
14681468
// Note that other checks (such as denying `dyn Send` -> `dyn
14691469
// Debug`) are in `rustc_hir_typeck`.
1470-
if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind()
1470+
if let ty::Dynamic(src_tty, src_lt, ty::Dyn) = *src_tail.kind()
14711471
&& let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind()
14721472
&& src_tty.principal().is_some()
14731473
&& dst_tty.principal().is_some()
14741474
{
14751475
// Remove auto traits.
1476-
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
1476+
// Auto trait checks are handled in `rustc_hir_typeck`.
14771477
let src_obj = Ty::new_dynamic(
14781478
tcx,
14791479
tcx.mk_poly_existential_predicates(
14801480
&src_tty.without_auto_traits().collect::<Vec<_>>(),
14811481
),
1482-
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
1483-
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
1484-
dst_lt,
1482+
src_lt,
14851483
ty::Dyn,
14861484
);
14871485
let dst_obj = Ty::new_dynamic(
@@ -1495,6 +1493,22 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14951493

14961494
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
14971495

1496+
// Trait parameters are Invariant, the only part that actually has subtyping
1497+
// here is the lifetime bound of the dyn-type.
1498+
//
1499+
// For example in `dyn Trait<'a> + 'b <: dyn Trait<'c> + 'd` we would require
1500+
// that `'a == 'c` but only that `'b: 'd`.
1501+
//
1502+
// We must not allow freely casting lifetime bounds of dyn-types as it may allow
1503+
// for inaccessible VTable methods being callable: #136702
1504+
//
1505+
// We don't enforce this for casts of principal-less dyn types as their VTables do
1506+
// not contain any functions with `Self: 'a` bounds that could start holding after
1507+
// a pointer cast.
1508+
//
1509+
// We also don't enforce this for casts of pointers to pointers to dyn types. E.g.
1510+
// `*mut *mut dyn Trait + 'a -> *mut *mut dyn Trait + 'static` is allowed. This is
1511+
// fine because there is no actual VTable in play.
14981512
self.sub_types(
14991513
src_obj,
15001514
dst_obj,

library/std/src/thread/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -578,8 +578,11 @@ impl Builder {
578578
let main = Box::new(main);
579579
// SAFETY: dynamic size and alignment of the Box remain the same. See below for why the
580580
// lifetime change is justified.
581-
let main =
582-
unsafe { Box::from_raw(Box::into_raw(main) as *mut (dyn FnOnce() + Send + 'static)) };
581+
let main = unsafe {
582+
let ptr = Box::into_raw(main) as *mut (dyn FnOnce() + Send + '_);
583+
let ptr: *mut (dyn FnOnce() + Send + 'static) = crate::mem::transmute(ptr);
584+
Box::from_raw(ptr)
585+
};
583586

584587
Ok(JoinInner {
585588
// SAFETY:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ check-pass
2+
3+
trait Trait {
4+
fn foo(&self) {}
5+
}
6+
7+
fn bar<'a>(a: *mut *mut (dyn Trait + 'a)) -> *mut *mut (dyn Trait + 'static) {
8+
a as _
9+
}
10+
11+
fn main() {}

tests/ui/cast/ptr-to-ptr-different-regions.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
//@ check-pass
2-
31
// https://github.com/rust-lang/rust/issues/113257
42

53
#![deny(trivial_casts)] // The casts here are not trivial.
64

7-
struct Foo<'a> { a: &'a () }
5+
struct Foo<'a> {
6+
a: &'a (),
7+
}
88

99
fn extend_lifetime_very_very_safely<'a>(v: *const Foo<'a>) -> *const Foo<'static> {
1010
// This should pass because raw pointer casts can do anything they want.
@@ -15,6 +15,7 @@ trait Trait {}
1515

1616
fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
1717
ptr as _
18+
//~^ ERROR: lifetime may not live long enough
1819
}
1920

2021
fn main() {
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/ptr-to-ptr-different-regions.rs:17:5
3+
|
4+
LL | fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
5+
| -- lifetime `'a` defined here
6+
LL | ptr as _
7+
| ^^^^^^^^ returning this value requires that `'a` must outlive `'static`
8+
|
9+
= note: requirement occurs because of a mutable pointer to `dyn Trait`
10+
= note: mutable pointers are invariant over their type parameter
11+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
12+
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `ptr`
13+
|
14+
LL | fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'a) {
15+
| ~~
16+
help: alternatively, add an explicit `'static` bound to this reference
17+
|
18+
LL | fn assert_static<'a>(ptr: *mut (dyn Trait + 'static)) -> *mut (dyn Trait + 'static) {
19+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
20+
21+
error: aborting due to 1 previous error
22+
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait Trait {
2+
fn foo(&self) {}
3+
}
4+
5+
struct MyWrap<T: ?Sized>(T);
6+
7+
fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'a)>) -> *mut MyWrap<(dyn Trait + 'static)> {
8+
a as _
9+
//~^ ERROR: lifetime may not live long enough
10+
}
11+
12+
fn main() {}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error: lifetime may not live long enough
2+
--> $DIR/ptr-to-ptr-indirect-different-regions.rs:8:5
3+
|
4+
LL | fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'a)>) -> *mut MyWrap<(dyn Trait + 'static)> {
5+
| -- lifetime `'a` defined here
6+
LL | a as _
7+
| ^^^^^^ returning this value requires that `'a` must outlive `'static`
8+
|
9+
= note: requirement occurs because of a mutable pointer to `MyWrap<dyn Trait>`
10+
= note: mutable pointers are invariant over their type parameter
11+
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
12+
note: raw pointer casts of trait objects do not cast away lifetimes
13+
--> $DIR/ptr-to-ptr-indirect-different-regions.rs:8:5
14+
|
15+
LL | a as _
16+
| ^^^^^^
17+
= note: this was previously accepted by the compiler but was changed recently
18+
= help: see <https://github.com/rust-lang/rust/issues/141402> for more information
19+
help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `a`
20+
|
21+
LL - fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'a)>) -> *mut MyWrap<(dyn Trait + 'static)> {
22+
LL + fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'a)>) -> *mut MyWrap<(dyn Trait + 'a)> {
23+
|
24+
help: alternatively, add an explicit `'static` bound to this reference
25+
|
26+
LL - fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'a)>) -> *mut MyWrap<(dyn Trait + 'static)> {
27+
LL + fn bar<'a>(a: *mut MyWrap<(dyn Trait + 'static)>) -> *mut MyWrap<(dyn Trait + 'static)> {
28+
|
29+
30+
error: aborting due to 1 previous error
31+

tests/ui/cast/ptr-to-trait-obj-ok.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn remove_auto<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut dyn Trait<'a> {
66
x as _
77
}
88

9-
fn cast_inherent_lt<'a, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) {
9+
fn cast_inherent_lt<'a: 'b, 'b>(x: *mut (dyn Trait<'static> + 'a)) -> *mut (dyn Trait<'static> + 'b) {
1010
x as _
1111
}
1212

@@ -29,7 +29,7 @@ fn remove_auto_wrap<'a>(x: *mut (dyn Trait<'a> + Send)) -> *mut Wrapper<dyn Trai
2929
x as _
3030
}
3131

32-
fn cast_inherent_lt_wrap<'a, 'b>(
32+
fn cast_inherent_lt_wrap<'a: 'b, 'b>(
3333
x: *mut (dyn Trait<'static> + 'a),
3434
) -> *mut Wrapper<dyn Trait<'static> + 'b> {
3535
x as _

0 commit comments

Comments
 (0)