diff options
| author | Jack Wrenn <jack@wrenn.fyi> | 2024-03-13 00:11:36 +0000 |
|---|---|---|
| committer | Jack Wrenn <jack@wrenn.fyi> | 2024-03-13 15:53:48 +0000 |
| commit | 216df4a8e6358a515ba95fb1a92864d1b94c37f3 (patch) | |
| tree | 8bfa6be348f0cca0fc53705def0763e3647544b9 /compiler/rustc_transmute/src | |
| parent | a165f1f65015b1bd4afd2ec50700aaacf2e0c485 (diff) | |
| download | rust-216df4a8e6358a515ba95fb1a92864d1b94c37f3.tar.gz rust-216df4a8e6358a515ba95fb1a92864d1b94c37f3.zip | |
safe transmute: require that src referent is smaller than dst
The source referent absolutely must be smaller than the destination referent of a ref-to-ref transmute; the excess bytes referenced cannot arise from thin air, even if those bytes are uninitialized.
Diffstat (limited to 'compiler/rustc_transmute/src')
| -rw-r--r-- | compiler/rustc_transmute/src/layout/mod.rs | 21 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/layout/tree.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/lib.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_transmute/src/maybe_transmutable/mod.rs | 5 |
4 files changed, 39 insertions, 3 deletions
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index 0441b49cb14..a7c60c3b490 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -35,6 +35,8 @@ pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone { pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone { fn min_align(&self) -> usize; + fn size(&self) -> usize; + fn is_mutable(&self) -> bool; } @@ -48,6 +50,9 @@ impl Ref for ! { fn min_align(&self) -> usize { unreachable!() } + fn size(&self) -> usize { + unreachable!() + } fn is_mutable(&self) -> bool { unreachable!() } @@ -57,6 +62,7 @@ impl Ref for ! { pub mod rustc { use rustc_middle::mir::Mutability; use rustc_middle::ty::{self, Ty}; + use std::fmt::{self, Write}; /// A reference in the layout. #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] @@ -65,6 +71,7 @@ pub mod rustc { pub ty: Ty<'tcx>, pub mutability: Mutability, pub align: usize, + pub size: usize, } impl<'tcx> super::Ref for Ref<'tcx> { @@ -72,6 +79,10 @@ pub mod rustc { self.align } + fn size(&self) -> usize { + self.size + } + fn is_mutable(&self) -> bool { match self.mutability { Mutability::Mut => true, @@ -81,6 +92,16 @@ pub mod rustc { } impl<'tcx> Ref<'tcx> {} + impl<'tcx> fmt::Display for Ref<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_char('&')?; + if self.mutability == Mutability::Mut { + f.write_str("mut ")?; + } + self.ty.fmt(f) + } + } + /// A visibility node in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] pub enum Def<'tcx> { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 71b72828e4c..c2fc55542ff 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -372,12 +372,15 @@ pub(crate) mod rustc { } ty::Ref(lifetime, ty, mutability) => { - let align = layout_of(tcx, *ty)?.align(); + let layout = layout_of(tcx, *ty)?; + let align = layout.align(); + let size = layout.size(); Ok(Tree::Ref(Ref { lifetime: *lifetime, ty: *ty, mutability: *mutability, align, + size, })) } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index fefce2640eb..8f3af491453 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -23,7 +23,7 @@ pub struct Assume { #[derive(Debug, Hash, Eq, PartialEq, Clone)] pub enum Answer<R> { Yes, - No(Reason), + No(Reason<R>), If(Condition<R>), } @@ -42,7 +42,7 @@ pub enum Condition<R> { /// Answers "why wasn't the source type transmutable into the destination type?" #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] -pub enum Reason { +pub enum Reason<T> { /// The layout of the source type is unspecified. SrcIsUnspecified, /// The layout of the destination type is unspecified. @@ -53,6 +53,13 @@ pub enum Reason { DstMayHaveSafetyInvariants, /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. DstIsTooBig, + /// A referent of `Dst` is larger than a referent in `Src`. + DstRefIsTooBig { + /// The referent of the source type. + src: T, + /// The too-large referent of the destination type. + dst: T, + }, /// Src should have a stricter alignment than Dst, but it does not. DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize }, /// Can't go from shared pointer to unique pointer diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 0e05aa4d3b2..e9f425686c4 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -266,6 +266,11 @@ where src_min_align: src_ref.min_align(), dst_min_align: dst_ref.min_align(), }) + } else if dst_ref.size() > src_ref.size() { + Answer::No(Reason::DstRefIsTooBig { + src: src_ref, + dst: dst_ref, + }) } else { // ...such that `src` is transmutable into `dst`, if // `src_ref` is transmutability into `dst_ref`. |
