Skip to content

Commit 7424ce9

Browse files
Auto merge of #136776 - BoxyUwU:forbid_object_lifetime_casts, r=<try>
Forbid freely casting lifetime bounds of dyn-types
2 parents e22dab3 + d525233 commit 7424ce9

18 files changed

+537
-22
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: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,15 +1106,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11061106
self.prove_predicate(
11071107
ty::ClauseKind::WellFormed(src_ty.into()),
11081108
location.to_locations(),
1109-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1109+
ConstraintCategory::Cast {
1110+
is_raw_ptr_dyn_type_cast: false,
1111+
is_implicit_coercion,
1112+
unsize_to: None,
1113+
},
11101114
);
11111115

11121116
let src_ty = self.normalize(src_ty, location);
11131117
if let Err(terr) = self.sub_types(
11141118
src_ty,
11151119
*ty,
11161120
location.to_locations(),
1117-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1121+
ConstraintCategory::Cast {
1122+
is_raw_ptr_dyn_type_cast: false,
1123+
is_implicit_coercion,
1124+
unsize_to: None,
1125+
},
11181126
) {
11191127
span_mirbug!(
11201128
self,
@@ -1135,7 +1143,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11351143
self.prove_predicate(
11361144
ty::ClauseKind::WellFormed(src_ty.into()),
11371145
location.to_locations(),
1138-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1146+
ConstraintCategory::Cast {
1147+
is_raw_ptr_dyn_type_cast: false,
1148+
is_implicit_coercion,
1149+
unsize_to: None,
1150+
},
11391151
);
11401152

11411153
// The type that we see in the fcx is like
@@ -1148,7 +1160,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11481160
src_ty,
11491161
*ty,
11501162
location.to_locations(),
1151-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1163+
ConstraintCategory::Cast {
1164+
is_raw_ptr_dyn_type_cast: false,
1165+
is_implicit_coercion,
1166+
unsize_to: None,
1167+
},
11521168
) {
11531169
span_mirbug!(
11541170
self,
@@ -1177,7 +1193,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
11771193
ty_fn_ptr_from,
11781194
*ty,
11791195
location.to_locations(),
1180-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1196+
ConstraintCategory::Cast {
1197+
is_raw_ptr_dyn_type_cast: false,
1198+
is_implicit_coercion,
1199+
unsize_to: None,
1200+
},
11811201
) {
11821202
span_mirbug!(
11831203
self,
@@ -1210,7 +1230,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12101230
ty_fn_ptr_from,
12111231
*ty,
12121232
location.to_locations(),
1213-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1233+
ConstraintCategory::Cast {
1234+
is_raw_ptr_dyn_type_cast: false,
1235+
is_implicit_coercion,
1236+
unsize_to: None,
1237+
},
12141238
) {
12151239
span_mirbug!(
12161240
self,
@@ -1239,6 +1263,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12391263
trait_ref,
12401264
location.to_locations(),
12411265
ConstraintCategory::Cast {
1266+
is_raw_ptr_dyn_type_cast: false,
12421267
is_implicit_coercion,
12431268
unsize_to: Some(unsize_to),
12441269
},
@@ -1264,7 +1289,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
12641289
*ty_from,
12651290
*ty_to,
12661291
location.to_locations(),
1267-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1292+
ConstraintCategory::Cast {
1293+
is_raw_ptr_dyn_type_cast: false,
1294+
is_implicit_coercion,
1295+
unsize_to: None,
1296+
},
12681297
) {
12691298
span_mirbug!(
12701299
self,
@@ -1327,7 +1356,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
13271356
*ty_elem,
13281357
*ty_to,
13291358
location.to_locations(),
1330-
ConstraintCategory::Cast { is_implicit_coercion, unsize_to: None },
1359+
ConstraintCategory::Cast {
1360+
is_raw_ptr_dyn_type_cast: false,
1361+
is_implicit_coercion,
1362+
unsize_to: None,
1363+
},
13311364
) {
13321365
span_mirbug!(
13331366
self,
@@ -1484,11 +1517,12 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
14841517
trait_ref,
14851518
location.to_locations(),
14861519
ConstraintCategory::Cast {
1520+
is_raw_ptr_dyn_type_cast: false,
14871521
is_implicit_coercion: true,
14881522
unsize_to: None,
14891523
},
14901524
);
1491-
} else if let ty::Dynamic(src_tty, _src_lt) =
1525+
} else if let ty::Dynamic(src_tty, src_lt) =
14921526
*self.struct_tail(src.ty, location).kind()
14931527
&& let ty::Dynamic(dst_tty, dst_lt) =
14941528
*self.struct_tail(dst.ty, location).kind()
@@ -1503,15 +1537,13 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15031537
// Debug`) are in `rustc_hir_typeck`.
15041538

15051539
// Remove auto traits.
1506-
// Auto trait checks are handled in `rustc_hir_typeck` as FCW.
1540+
// Auto trait checks are handled in `rustc_hir_typeck`.
15071541
let src_obj = Ty::new_dynamic(
15081542
tcx,
15091543
tcx.mk_poly_existential_predicates(
15101544
&src_tty.without_auto_traits().collect::<Vec<_>>(),
15111545
),
1512-
// FIXME: Once we disallow casting `*const dyn Trait + 'short`
1513-
// to `*const dyn Trait + 'long`, then this can just be `src_lt`.
1514-
dst_lt,
1546+
src_lt,
15151547
);
15161548
let dst_obj = Ty::new_dynamic(
15171549
tcx,
@@ -1523,16 +1555,47 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
15231555

15241556
debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj);
15251557

1558+
// Trait parameters are Invariant, the only part that actually has
1559+
// subtyping here is the lifetime bound of the dyn-type.
1560+
//
1561+
// For example in `dyn Trait<'a> + 'b <: dyn Trait<'c> + 'd` we would
1562+
// require that `'a == 'c` but only that `'b: 'd`.
1563+
//
1564+
// We must not allow freely casting lifetime bounds of dyn-types as it
1565+
// may allow for inaccessible VTable methods being callable: #136702
15261566
self.sub_types(
15271567
src_obj,
15281568
dst_obj,
15291569
location.to_locations(),
15301570
ConstraintCategory::Cast {
1571+
is_raw_ptr_dyn_type_cast: true,
15311572
is_implicit_coercion: false,
15321573
unsize_to: None,
15331574
},
15341575
)
15351576
.unwrap();
1577+
} else if let ty::Dynamic(src_tty, src_lt) =
1578+
*self.struct_tail(src.ty, location).kind()
1579+
&& let ty::Dynamic(dst_tty, dst_lt) =
1580+
*self.struct_tail(dst.ty, location).kind()
1581+
&& src_tty.principal().is_none()
1582+
&& dst_tty.principal().is_none()
1583+
{
1584+
// The principalless (no non-auto traits) case:
1585+
// You can only cast `dyn Send + 'long` to `dyn Send + 'short`.
1586+
self.constraints.outlives_constraints.push(OutlivesConstraint {
1587+
sup: src_lt.as_var(),
1588+
sub: dst_lt.as_var(),
1589+
locations: location.to_locations(),
1590+
span: location.to_locations().span(self.body),
1591+
category: ConstraintCategory::Cast {
1592+
is_raw_ptr_dyn_type_cast: true,
1593+
is_implicit_coercion: false,
1594+
unsize_to: None,
1595+
},
1596+
variance_info: ty::VarianceDiagInfo::default(),
1597+
from_closure: false,
1598+
});
15361599
}
15371600
}
15381601
CastKind::Transmute => {

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/mod.rs

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

587590
Ok(JoinInner {
588591
// 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: 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)