Skip to content

Commit fafb277

Browse files
committed
interpret: Immediate::offset: use shared sanity-check function to ensure invariant
1 parent e9df22f commit fafb277

File tree

3 files changed

+49
-31
lines changed

3 files changed

+49
-31
lines changed

compiler/rustc_const_eval/src/interpret/operand.rs

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -113,27 +113,46 @@ impl<Prov: Provenance> Immediate<Prov> {
113113
}
114114

115115
/// Assert that this immediate is a valid value for the given ABI.
116-
pub fn assert_matches_abi(self, abi: Abi, cx: &impl HasDataLayout) {
116+
pub fn assert_matches_abi(self, abi: Abi, msg: &str, cx: &impl HasDataLayout) {
117117
match (self, abi) {
118118
(Immediate::Scalar(scalar), Abi::Scalar(s)) => {
119-
assert_eq!(scalar.size(), s.size(cx));
119+
assert_eq!(scalar.size(), s.size(cx), "{msg}: scalar value has wrong size");
120120
if !matches!(s.primitive(), abi::Pointer(..)) {
121-
assert!(matches!(scalar, Scalar::Int(..)));
121+
assert!(
122+
matches!(scalar, Scalar::Int(..)),
123+
"{msg}: scalar value should be an integer, but has provenance"
124+
);
122125
}
123126
}
124127
(Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
125-
assert_eq!(a_val.size(), a.size(cx));
128+
assert_eq!(
129+
a_val.size(),
130+
a.size(cx),
131+
"{msg}: first component of scalar pair has wrong size"
132+
);
126133
if !matches!(a.primitive(), abi::Pointer(..)) {
127-
assert!(matches!(a_val, Scalar::Int(..)));
134+
assert!(
135+
matches!(a_val, Scalar::Int(..)),
136+
"{msg}: first component of scalar pair should be an integer, but has provenance"
137+
);
128138
}
129-
assert_eq!(b_val.size(), b.size(cx));
139+
assert_eq!(
140+
b_val.size(),
141+
b.size(cx),
142+
"{msg}: second component of scalar pair has wrong size"
143+
);
130144
if !matches!(b.primitive(), abi::Pointer(..)) {
131-
assert!(matches!(b_val, Scalar::Int(..)));
145+
assert!(
146+
matches!(b_val, Scalar::Int(..)),
147+
"{msg}: second component of scalar pair should be an integer, but has provenance"
148+
);
132149
}
133150
}
134-
(Immediate::Uninit, _) => {}
151+
(Immediate::Uninit, _) => {
152+
assert!(abi.is_sized(), "{msg}: unsized immediates are not a thing");
153+
}
135154
_ => {
136-
bug!("value {self:?} does not match ABI {abi:?})",)
155+
bug!("{msg}: value {self:?} does not match ABI {abi:?})",)
137156
}
138157
}
139158
}
@@ -240,6 +259,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
240259

241260
#[inline(always)]
242261
pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
262+
// Without a `cx` we cannot call `assert_matches_abi`.
243263
debug_assert!(
244264
match (imm, layout.abi) {
245265
(Immediate::Scalar(..), Abi::Scalar(..)) => true,
@@ -260,7 +280,6 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
260280

261281
#[inline]
262282
pub fn from_scalar_int(s: ScalarInt, layout: TyAndLayout<'tcx>) -> Self {
263-
assert_eq!(s.size(), layout.size);
264283
Self::from_scalar(Scalar::from(s), layout)
265284
}
266285

@@ -333,7 +352,10 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
333352
/// given layout.
334353
// Not called `offset` to avoid confusion with the trait method.
335354
fn offset_(&self, offset: Size, layout: TyAndLayout<'tcx>, cx: &impl HasDataLayout) -> Self {
336-
debug_assert!(layout.is_sized(), "unsized immediates are not a thing");
355+
// Verify that the input matches its type.
356+
if cfg!(debug_assertions) {
357+
self.assert_matches_abi(self.layout.abi, "invalid input to Immediate::offset", cx);
358+
}
337359
// `ImmTy` have already been checked to be in-bounds, so we can just check directly if this
338360
// remains in-bounds. This cannot actually be violated since projections are type-checked
339361
// and bounds-checked.
@@ -367,32 +389,14 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
367389
// the field covers the entire type
368390
_ if layout.size == self.layout.size => {
369391
assert_eq!(offset.bytes(), 0);
370-
assert!(
371-
match (self.layout.abi, layout.abi) {
372-
(Abi::Scalar(l), Abi::Scalar(r)) => l.size(cx) == r.size(cx),
373-
(Abi::ScalarPair(l1, l2), Abi::ScalarPair(r1, r2)) =>
374-
l1.size(cx) == r1.size(cx) && l2.size(cx) == r2.size(cx),
375-
_ => false,
376-
},
377-
"cannot project into {} immediate with equally-sized field {}\nouter ABI: {:#?}\nfield ABI: {:#?}",
378-
self.layout.ty,
379-
layout.ty,
380-
self.layout.abi,
381-
layout.abi,
382-
);
383392
**self
384393
}
385394
// extract fields from types with `ScalarPair` ABI
386395
(Immediate::ScalarPair(a_val, b_val), Abi::ScalarPair(a, b)) => {
387-
assert_matches!(layout.abi, Abi::Scalar(..));
388396
Immediate::from(if offset.bytes() == 0 {
389-
// It is "okay" to transmute from `usize` to a pointer (GVN relies on that).
390-
// So only compare the size.
391-
assert_eq!(layout.size, a.size(cx));
392397
a_val
393398
} else {
394399
assert_eq!(offset, a.size(cx).align_to(b.align(cx).abi));
395-
assert_eq!(layout.size, b.size(cx));
396400
b_val
397401
})
398402
}
@@ -404,6 +408,8 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
404408
self.layout
405409
),
406410
};
411+
// Ensure the new layout matches the new value.
412+
inner_val.assert_matches_abi(layout.abi, "invalid field type in Immediate::offset", cx);
407413

408414
ImmTy::from_immediate(inner_val, layout)
409415
}

compiler/rustc_const_eval/src/interpret/place.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,11 @@ where
653653
}
654654
// Double-check that the value we are storing and the local fit to each other.
655655
if cfg!(debug_assertions) {
656-
src.assert_matches_abi(local_layout.abi, self);
656+
src.assert_matches_abi(
657+
local_layout.abi,
658+
"invalid immediate for given destination place",
659+
self,
660+
);
657661
}
658662
}
659663
Left(mplace) => {
@@ -673,7 +677,11 @@ where
673677
dest: MemPlace<M::Provenance>,
674678
) -> InterpResult<'tcx> {
675679
if cfg!(debug_assertions) {
676-
value.assert_matches_abi(layout.abi, self);
680+
value.assert_matches_abi(
681+
layout.abi,
682+
"invalid immediate for given destination place",
683+
self,
684+
);
677685
}
678686
// Note that it is really important that the type here is the right one, and matches the
679687
// type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here

compiler/rustc_const_eval/src/interpret/projection.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug {
8282
self.offset_with_meta(offset, OffsetMode::Inbounds, MemPlaceMeta::None, layout, ecx)
8383
}
8484

85+
/// This does an offset-by-zero, which is effectively a transmute. Note however that
86+
/// not all transmutes are supported by all projectables -- specifically, if this is an
87+
/// `OpTy` or `ImmTy`, the new layout must have almost the same ABI as the old one
88+
/// (only changing the `valid_range` is allowed and turning integers into pointers).
8589
fn transmute<M: Machine<'tcx, Provenance = Prov>>(
8690
&self,
8791
layout: TyAndLayout<'tcx>,

0 commit comments

Comments
 (0)