Skip to content

Commit f38653b

Browse files
committed
Forbid object lifetime changing pointer casts
1 parent 2e667b0 commit f38653b

14 files changed

+254
-19
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
410410
cx.add_sized_or_copy_bound_info(err, category, &path);
411411

412412
if let ConstraintCategory::Cast {
413+
is_raw_ptr_dyn_type_cast: _,
413414
is_implicit_coercion: true,
414415
unsize_to: Some(unsize_ty),
415416
} = category

compiler/rustc_borrowck/src/diagnostics/region_errors.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,23 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
541541
self.add_placeholder_from_predicate_note(&mut diag, &path);
542542
self.add_sized_or_copy_bound_info(&mut diag, category, &path);
543543

544+
for constraint in &path {
545+
if let ConstraintCategory::Cast { is_raw_ptr_dyn_type_cast: true, .. } =
546+
constraint.category
547+
{
548+
diag.span_note(
549+
constraint.span,
550+
format!("raw pointer casts of trait objects do not cast away lifetimes"),
551+
);
552+
diag.note(format!(
553+
"this was previously accepted by the compiler but was changed recently"
554+
));
555+
diag.help(format!(
556+
"see <https://github.com/rust-lang/rust/issues/141402> for more information"
557+
));
558+
}
559+
}
560+
544561
self.buffer_error(diag);
545562
}
546563

compiler/rustc_borrowck/src/region_infer/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
16971697
// should be as limited as possible; the note is prone to false positives and this
16981698
// constraint usually isn't best to blame.
16991699
ConstraintCategory::Cast {
1700+
is_raw_ptr_dyn_type_cast: _,
17001701
unsize_to: Some(unsize_ty),
17011702
is_implicit_coercion: true,
17021703
} if to_region == self.universal_regions().fr_static

compiler/rustc_borrowck/src/type_check/mod.rs

Lines changed: 63 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,15 +1113,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11131113
self.prove_predicate(
11141114
ty::ClauseKind::WellFormed(src_ty.into()),
11151115
location.to_locations(),
1116-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1116+
ConstraintCategory::Cast {
1117+
is_raw_ptr_dyn_type_cast: false,
1118+
is_implicit_coercion,
1119+
unsize_to: None,
1120+
},
11171121
);
11181122

11191123
let src_ty = self.normalize(src_ty, location);
11201124
if let Err(terr) = self.sub_types(
11211125
src_ty,
11221126
*ty,
11231127
location.to_locations(),
1124-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1128+
ConstraintCategory::Cast {
1129+
is_raw_ptr_dyn_type_cast: false,
1130+
is_implicit_coercion,
1131+
unsize_to: None,
1132+
},
11251133
) {
11261134
span_mirbug!(
11271135
self,
@@ -1142,7 +1150,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11421150
self.prove_predicate(
11431151
ty::ClauseKind::WellFormed(src_ty.into()),
11441152
location.to_locations(),
1145-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1153+
ConstraintCategory::Cast {
1154+
is_raw_ptr_dyn_type_cast: false,
1155+
is_implicit_coercion,
1156+
unsize_to: None,
1157+
},
11461158
);
11471159

11481160
// The type that we see in the fcx is like
@@ -1155,7 +1167,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11551167
src_ty,
11561168
*ty,
11571169
location.to_locations(),
1158-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1170+
ConstraintCategory::Cast {
1171+
is_raw_ptr_dyn_type_cast: false,
1172+
is_implicit_coercion,
1173+
unsize_to: None,
1174+
},
11591175
) {
11601176
span_mirbug!(
11611177
self,
@@ -1184,7 +1200,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11841200
ty_fn_ptr_from,
11851201
*ty,
11861202
location.to_locations(),
1187-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1203+
ConstraintCategory::Cast {
1204+
is_raw_ptr_dyn_type_cast: false,
1205+
is_implicit_coercion,
1206+
unsize_to: None,
1207+
},
11881208
) {
11891209
span_mirbug!(
11901210
self,
@@ -1217,7 +1237,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12171237
ty_fn_ptr_from,
12181238
*ty,
12191239
location.to_locations(),
1220-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1240+
ConstraintCategory::Cast {
1241+
is_raw_ptr_dyn_type_cast: false,
1242+
is_implicit_coercion,
1243+
unsize_to: None,
1244+
},
12211245
) {
12221246
span_mirbug!(
12231247
self,
@@ -1246,6 +1270,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12461270
trait_ref,
12471271
location.to_locations(),
12481272
ConstraintCategory::Cast {
1273+
is_raw_ptr_dyn_type_cast: false,
12491274
is_implicit_coercion,
12501275
unsize_to: Some(unsize_to),
12511276
},
@@ -1271,7 +1296,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12711296
*ty_from,
12721297
*ty_to,
12731298
location.to_locations(),
1274-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1299+
ConstraintCategory::Cast {
1300+
is_raw_ptr_dyn_type_cast: false,
1301+
is_implicit_coercion,
1302+
unsize_to: None,
1303+
},
12751304
) {
12761305
span_mirbug!(
12771306
self,
@@ -1334,7 +1363,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
13341363
*ty_elem,
13351364
*ty_to,
13361365
location.to_locations(),
1337-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1366+
ConstraintCategory::Cast {
1367+
is_raw_ptr_dyn_type_cast: false,
1368+
is_implicit_coercion,
1369+
unsize_to: None,
1370+
},
13381371
) {
13391372
span_mirbug!(
13401373
self,
@@ -1491,11 +1524,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14911524
trait_ref,
14921525
location.to_locations(),
14931526
ConstraintCategory::Cast {
1527+
is_raw_ptr_dyn_type_cast: false,
14941528
is_implicit_coercion: true,
14951529
unsize_to: None,
14961530
},
14971531
);
1498-
} else if let ty::Dynamic(src_tty, _src_lt) =
1532+
} else if let ty::Dynamic(src_tty, src_lt) =
14991533
*self.struct_tail(src.ty, location).kind()
15001534
&& let ty::Dynamic(dst_tty, dst_lt) =
15011535
*self.struct_tail(dst.ty, location).kind()
@@ -1510,15 +1544,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15101544
// Debug`) are in `rustc_hir_typeck`.
15111545

15121546
// Remove auto traits.
1513-
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
1547+
// Auto trait checks are handled in `rustc_hir_typeck`.
15141548
let src_obj = Ty::new_dynamic(
15151549
tcx,
15161550
tcx.mk_poly_existential_predicates(
15171551
&src_tty.without_auto_traits().collect::<Vec<_>>(),
15181552
),
1519-
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
1520-
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
1521-
dst_lt,
1553+
src_lt,
15221554
);
15231555
let dst_obj = Ty::new_dynamic(
15241556
tcx,
@@ -1530,11 +1562,29 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15301562

15311563
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
15321564

1565+
// Trait parameters are Invariant, the only part that actually has
1566+
// subtyping here is the lifetime bound of the dyn-type.
1567+
//
1568+
// For example in `dyn Trait<'a> + 'b <: dyn Trait<'c> + 'd` we would
1569+
// require that `'a == 'c` but only that `'b: 'd`.
1570+
//
1571+
// We must not allow freely casting lifetime bounds of dyn-types as it
1572+
// may allow for inaccessible VTable methods being callable: #136702
1573+
//
1574+
// We don't enforce this for casts of principal-less dyn types as their
1575+
// VTables do not contain any functions with `Self: 'a` bounds that
1576+
// could start holding after a pointer cast.
1577+
//
1578+
// We also don't enforce this for casts of pointers to pointers to dyn
1579+
// types. E.g. `*mut *mut dyn Trait + 'a -> *mut *mut dyn Trait +
1580+
// 'static` is allowed. This is fine because there is no actual VTable
1581+
// in play.
15331582
self.sub_types(
15341583
src_obj,
15351584
dst_obj,
15361585
location.to_locations(),
15371586
ConstraintCategory::Cast {
1587+
is_raw_ptr_dyn_type_cast: true,
15381588
is_implicit_coercion: false,
15391589
unsize_to: None,
15401590
},

compiler/rustc_middle/src/mir/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ pub enum ConstraintCategory<'tcx> {
108108
UseAsStatic,
109109
TypeAnnotation(AnnotationSource),
110110
Cast {
111+
is_raw_ptr_dyn_type_cast: bool,
111112
/// Whether this cast is a coercion that was automatically inserted by the compiler.
112113
is_implicit_coercion: bool,
113114
/// Whether this is an unsizing coercion and if yes, this contains the target type.

library/std/src/thread/lifecycle.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,12 @@ where
111111
// SAFETY: dynamic size and alignment of the Box remain the same. See below for why the
112112
// lifetime change is justified.
113113
let rust_start = unsafe {
114-
Box::from_raw(Box::into_raw(Box::new(rust_start)) as *mut (dyn FnOnce() + Send + 'static))
114+
let ptr = Box::into_raw(Box::new(rust_start));
115+
let ptr = crate::mem::transmute::<
116+
*mut (dyn FnOnce() + Send + '_),
117+
*mut (dyn FnOnce() + Send + 'static),
118+
>(ptr);
119+
Box::from_raw(ptr)
115120
};
116121

117122
let init = Box::new(ThreadInit { handle: thread.clone(), rust_start });
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: 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-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+
note: raw pointer casts of trait objects do not cast away lifetimes
13+
--> $DIR/ptr-to-ptr-different-regions.rs:17:5
14+
|
15+
LL | ptr 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 `ptr`
20+
|
21+
LL - fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
22+
LL + fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'a) {
23+
|
24+
help: alternatively, add an explicit `'static` bound to this reference
25+
|
26+
LL - fn assert_static<'a>(ptr: *mut (dyn Trait + 'a)) -> *mut (dyn Trait + 'static) {
27+
LL + fn assert_static<'a>(ptr: *mut (dyn Trait + 'static)) -> *mut (dyn Trait + 'static) {
28+
|
29+
30+
error: aborting due to 1 previous error
31+
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() {}

0 commit comments

Comments
 (0)