Skip to content

Commit 619d38a

Browse files
authored
Rollup merge of rust-lang#66147 - RalfJung:no-scalar-ptr, r=oli-obk
Miri: Refactor to_scalar_ptr out of existence `to_scalar_ptr` is somewhat subtle as it just throws away the 2nd component of a `ScalarPair` if there is one -- without any check if this is truly a pointer or so. And indeed we used it wrong on two occasions! So I fixed those two, and then refactored things such that everyone calls `ref_to_mplace` instead (which they did anyway, I just moved up the calls), which is the only place that should interpret a `ScalarPair` as a wide ptr -- and it checks the type first. Thus we can remove `to_scalar_ptr` and `to_meta`. r? @oli-obk
2 parents f573bd8 + 2312a56 commit 619d38a

File tree

6 files changed

+38
-68
lines changed

6 files changed

+38
-68
lines changed

src/librustc_mir/interpret/cast.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
260260

261261
match (&src_pointee_ty.kind, &dest_pointee_ty.kind) {
262262
(&ty::Array(_, length), &ty::Slice(_)) => {
263-
let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
263+
let ptr = self.read_immediate(src)?.to_scalar()?;
264264
// u64 cast is from usize to u64, which is always good
265265
let val = Immediate::new_slice(
266266
ptr,
@@ -279,7 +279,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
279279
(_, &ty::Dynamic(ref data, _)) => {
280280
// Initial cast from sized to dyn trait
281281
let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
282-
let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
282+
let ptr = self.read_immediate(src)?.to_scalar()?;
283283
let val = Immediate::new_dyn_trait(ptr, vtable);
284284
self.write_immediate(val, dest)
285285
}

src/librustc_mir/interpret/intern.rs

+10-12
Original file line numberDiff line numberDiff line change
@@ -192,20 +192,18 @@ for
192192
let ty = mplace.layout.ty;
193193
if let ty::Ref(_, referenced_ty, mutability) = ty.kind {
194194
let value = self.ecx.read_immediate(mplace.into())?;
195+
let mplace = self.ecx.ref_to_mplace(value)?;
195196
// Handle trait object vtables
196-
if let Ok(meta) = value.to_meta() {
197-
if let ty::Dynamic(..) =
198-
self.ecx.tcx.struct_tail_erasing_lifetimes(
199-
referenced_ty, self.ecx.param_env).kind
200-
{
201-
if let Ok(vtable) = meta.unwrap().to_ptr() {
202-
// explitly choose `Immutable` here, since vtables are immutable, even
203-
// if the reference of the fat pointer is mutable
204-
self.intern_shallow(vtable.alloc_id, Mutability::Immutable, None)?;
205-
}
197+
if let ty::Dynamic(..) =
198+
self.ecx.tcx.struct_tail_erasing_lifetimes(
199+
referenced_ty, self.ecx.param_env).kind
200+
{
201+
if let Ok(vtable) = mplace.meta.unwrap().to_ptr() {
202+
// explitly choose `Immutable` here, since vtables are immutable, even
203+
// if the reference of the fat pointer is mutable
204+
self.intern_shallow(vtable.alloc_id, Mutability::Immutable, None)?;
206205
}
207206
}
208-
let mplace = self.ecx.ref_to_mplace(value)?;
209207
// Check if we have encountered this pointer+layout combination before.
210208
// Only recurse for allocation-backed pointers.
211209
if let Scalar::Ptr(ptr) = mplace.ptr {
@@ -230,7 +228,7 @@ for
230228
ty::Array(_, n)
231229
if n.eval_usize(self.ecx.tcx.tcx, self.ecx.param_env) == 0 => {}
232230
ty::Slice(_)
233-
if value.to_meta().unwrap().unwrap().to_usize(self.ecx)? == 0 => {}
231+
if mplace.meta.unwrap().to_usize(self.ecx)? == 0 => {}
234232
_ => bug!("const qualif failed to prevent mutable references"),
235233
}
236234
},

src/librustc_mir/interpret/operand.rs

-20
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,6 @@ impl<'tcx, Tag> Immediate<Tag> {
8282
Immediate::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?))
8383
}
8484
}
85-
86-
/// Converts the immediate into a pointer (or a pointer-sized integer).
87-
/// Throws away the second half of a ScalarPair!
88-
#[inline]
89-
pub fn to_scalar_ptr(self) -> InterpResult<'tcx, Scalar<Tag>> {
90-
match self {
91-
Immediate::Scalar(ptr) |
92-
Immediate::ScalarPair(ptr, _) => ptr.not_undef(),
93-
}
94-
}
95-
96-
/// Converts the value into its metadata.
97-
/// Throws away the first half of a ScalarPair!
98-
#[inline]
99-
pub fn to_meta(self) -> InterpResult<'tcx, Option<Scalar<Tag>>> {
100-
Ok(match self {
101-
Immediate::Scalar(_) => None,
102-
Immediate::ScalarPair(_, meta) => Some(meta.not_undef()?),
103-
})
104-
}
10585
}
10686

10787
// ScalarPair needs a type to interpret, so we often have an immediate and a type together

src/librustc_mir/interpret/place.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -287,17 +287,23 @@ where
287287
&self,
288288
val: ImmTy<'tcx, M::PointerTag>,
289289
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
290-
let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
290+
let pointee_type = val.layout.ty.builtin_deref(true)
291+
.expect("`ref_to_mplace` called on non-ptr type")
292+
.ty;
291293
let layout = self.layout_of(pointee_type)?;
294+
let (ptr, meta) = match *val {
295+
Immediate::Scalar(ptr) => (ptr.not_undef()?, None),
296+
Immediate::ScalarPair(ptr, meta) => (ptr.not_undef()?, Some(meta.not_undef()?)),
297+
};
292298

293299
let mplace = MemPlace {
294-
ptr: val.to_scalar_ptr()?,
300+
ptr,
295301
// We could use the run-time alignment here. For now, we do not, because
296302
// the point of tracking the alignment here is to make sure that the *static*
297303
// alignment information emitted with the loads is correct. The run-time
298304
// alignment can only be more restrictive.
299305
align: layout.align.abi,
300-
meta: val.to_meta()?,
306+
meta,
301307
};
302308
Ok(MPlaceTy { mplace, layout })
303309
}

src/librustc_mir/interpret/validity.rs

+15-29
Original file line numberDiff line numberDiff line change
@@ -388,44 +388,31 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
388388
}
389389
}
390390
ty::RawPtr(..) => {
391-
// Check pointer part.
392-
if self.ref_tracking_for_consts.is_some() {
393-
// Integers/floats in CTFE: For consistency with integers, we do not
394-
// accept undef.
395-
let _ptr = try_validation!(value.to_scalar_ptr(),
396-
"undefined address in raw pointer", self.path);
397-
} else {
398-
// Remain consistent with `usize`: Accept anything.
399-
}
400-
401-
// Check metadata.
402-
let meta = try_validation!(value.to_meta(),
403-
"uninitialized data in wide pointer metadata", self.path);
404-
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
405-
if layout.is_unsized() {
406-
self.check_wide_ptr_meta(meta, layout)?;
391+
// We are conservative with undef for integers, but try to
392+
// actually enforce our current rules for raw pointers.
393+
let place = try_validation!(self.ecx.ref_to_mplace(value),
394+
"undefined pointer", self.path);
395+
if place.layout.is_unsized() {
396+
self.check_wide_ptr_meta(place.meta, place.layout)?;
407397
}
408398
}
409399
_ if ty.is_box() || ty.is_region_ptr() => {
410400
// Handle wide pointers.
411401
// Check metadata early, for better diagnostics
412-
let ptr = try_validation!(value.to_scalar_ptr(),
413-
"undefined address in pointer", self.path);
414-
let meta = try_validation!(value.to_meta(),
415-
"uninitialized data in wide pointer metadata", self.path);
416-
let layout = self.ecx.layout_of(value.layout.ty.builtin_deref(true).unwrap().ty)?;
417-
if layout.is_unsized() {
418-
self.check_wide_ptr_meta(meta, layout)?;
402+
let place = try_validation!(self.ecx.ref_to_mplace(value),
403+
"undefined pointer", self.path);
404+
if place.layout.is_unsized() {
405+
self.check_wide_ptr_meta(place.meta, place.layout)?;
419406
}
420407
// Make sure this is dereferencable and all.
421-
let (size, align) = self.ecx.size_and_align_of(meta, layout)?
408+
let (size, align) = self.ecx.size_and_align_of(place.meta, place.layout)?
422409
// for the purpose of validity, consider foreign types to have
423410
// alignment and size determined by the layout (size will be 0,
424411
// alignment should take attributes into account).
425-
.unwrap_or_else(|| (layout.size, layout.align.abi));
412+
.unwrap_or_else(|| (place.layout.size, place.layout.align.abi));
426413
let ptr: Option<_> = match
427414
self.ecx.memory.check_ptr_access_align(
428-
ptr,
415+
place.ptr,
429416
size,
430417
Some(align),
431418
CheckInAllocMsg::InboundsTest,
@@ -435,7 +422,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
435422
Err(err) => {
436423
info!(
437424
"{:?} did not pass access check for size {:?}, align {:?}",
438-
ptr, size, align
425+
place.ptr, size, align
439426
);
440427
match err.kind {
441428
err_unsup!(InvalidNullPointerUsage) =>
@@ -459,7 +446,6 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
459446
};
460447
// Recursive checking
461448
if let Some(ref mut ref_tracking) = self.ref_tracking_for_consts {
462-
let place = self.ecx.ref_to_mplace(value)?;
463449
if let Some(ptr) = ptr { // not a ZST
464450
// Skip validation entirely for some external statics
465451
let alloc_kind = self.ecx.tcx.alloc_map.lock().get(ptr.alloc_id);
@@ -627,7 +613,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
627613
// reject it. However, that's good: We don't inherently want
628614
// to reject those pointers, we just do not have the machinery to
629615
// talk about parts of a pointer.
630-
// We also accept undef, for consistency with the type-based checks.
616+
// We also accept undef, for consistency with the slow path.
631617
match self.ecx.memory.get(ptr.alloc_id)?.check_bytes(
632618
self.ecx,
633619
ptr,

src/test/ui/consts/const-eval/ub-wide-ptr.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value
4242
--> $DIR/ub-wide-ptr.rs:107:1
4343
|
4444
LL | const SLICE_LENGTH_UNINIT: &[u8] = unsafe { SliceTransmute { addr: 42 }.slice};
45-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
4646
|
4747
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
4848

@@ -90,7 +90,7 @@ error[E0080]: it is undefined behavior to use this value
9090
--> $DIR/ub-wide-ptr.rs:133:1
9191
|
9292
LL | const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe { SliceTransmute { addr: 42 }.raw_slice};
93-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized data in wide pointer metadata
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered undefined pointer
9494
|
9595
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
9696

0 commit comments

Comments
 (0)