Skip to content

Commit c3fc4f0

Browse files
committed
catch errors more locally around read_discriminant
1 parent 54d95ed commit c3fc4f0

File tree

4 files changed

+43
-24
lines changed

4 files changed

+43
-24
lines changed

src/librustc_mir/interpret/validity.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -276,19 +276,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
276276
}
277277
}
278278

279-
fn visit_elem(
279+
fn with_elem<R>(
280280
&mut self,
281-
new_op: OpTy<'tcx, M::PointerTag>,
282281
elem: PathElem,
283-
) -> InterpResult<'tcx> {
282+
f: impl FnOnce(&mut Self) -> InterpResult<'tcx, R>,
283+
) -> InterpResult<'tcx, R> {
284284
// Remember the old state
285285
let path_len = self.path.len();
286-
// Perform operation
286+
// Record new element
287287
self.path.push(elem);
288-
self.visit_value(new_op)?;
288+
// Perform operation
289+
let r = f(self)?;
289290
// Undo changes
290291
self.path.truncate(path_len);
291-
Ok(())
292+
// Done
293+
Ok(r)
292294
}
293295

294296
fn check_wide_ptr_meta(
@@ -649,6 +651,21 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
649651
&self.ecx
650652
}
651653

654+
fn read_discriminant(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, VariantIdx> {
655+
self.with_elem(PathElem::EnumTag, move |this| {
656+
Ok(try_validation!(
657+
this.ecx.read_discriminant(op),
658+
this.path,
659+
err_ub!(InvalidTag(val)) =>
660+
{ "{}", val } expected { "a valid enum tag" },
661+
err_ub!(InvalidUninitBytes(None)) =>
662+
{ "uninitialized bytes" } expected { "a valid enum tag" },
663+
err_unsup!(ReadPointerAsBytes) =>
664+
{ "a pointer" } expected { "a valid enum tag" },
665+
).1)
666+
})
667+
}
668+
652669
#[inline]
653670
fn visit_field(
654671
&mut self,
@@ -657,7 +674,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
657674
new_op: OpTy<'tcx, M::PointerTag>,
658675
) -> InterpResult<'tcx> {
659676
let elem = self.aggregate_field_path_elem(old_op.layout, field);
660-
self.visit_elem(new_op, elem)
677+
self.with_elem(elem, move |this| this.visit_value(new_op))
661678
}
662679

663680
#[inline]
@@ -673,7 +690,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
673690
ty::Generator(..) => PathElem::GeneratorState(variant_id),
674691
_ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
675692
};
676-
self.visit_elem(new_op, name)
693+
self.with_elem(name, move |this| this.visit_value(new_op))
677694
}
678695

679696
#[inline(always)]
@@ -696,18 +713,8 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
696713
// Sanity check: `builtin_deref` does not know any pointers that are not primitive.
697714
assert!(op.layout.ty.builtin_deref(true).is_none());
698715

699-
// Recursively walk the type. Translate some possible errors to something nicer.
700-
try_validation!(
701-
self.walk_value(op),
702-
self.path,
703-
err_ub!(InvalidTag(val)) =>
704-
{ "{}", val } expected { "a valid enum tag" },
705-
// `InvalidUninitBytes` can be caused by `read_discriminant` in Miri if all initialized tags are valid.
706-
err_ub!(InvalidUninitBytes(None)) =>
707-
{ "uninitialized bytes" } expected { "a valid enum tag" },
708-
err_unsup!(ReadPointerAsBytes) =>
709-
{ "a pointer" } expected { "plain (non-pointer) bytes" },
710-
);
716+
// Recursively walk the value at its type.
717+
self.walk_value(op)?;
711718

712719
// *After* all of this, check the ABI. We need to check the ABI to handle
713720
// types like `NonNull` where the `Scalar` info is more restrictive than what
@@ -822,6 +829,9 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
822829

823830
throw_validation_failure!(self.path, { "uninitialized bytes" })
824831
}
832+
err_unsup!(ReadPointerAsBytes) =>
833+
throw_validation_failure!(self.path, { "a pointer" } expected { "plain (non-pointer) bytes" }),
834+
825835
// Propagate upwards (that will also check for unexpected errors).
826836
_ => return Err(err),
827837
}

src/librustc_mir/interpret/visitor.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ macro_rules! make_value_visitor {
125125
fn ecx(&$($mutability)? self)
126126
-> &$($mutability)? InterpCx<'mir, 'tcx, M>;
127127

128+
/// `read_discriminant` can be hooked for better error messages.
129+
#[inline(always)]
130+
fn read_discriminant(
131+
&mut self,
132+
op: OpTy<'tcx, M::PointerTag>,
133+
) -> InterpResult<'tcx, VariantIdx> {
134+
Ok(self.ecx().read_discriminant(op)?.1)
135+
}
136+
128137
// Recursive actions, ready to be overloaded.
129138
/// Visits the given value, dispatching as appropriate to more specialized visitors.
130139
#[inline(always)]
@@ -245,7 +254,7 @@ macro_rules! make_value_visitor {
245254
// with *its* fields.
246255
Variants::Multiple { .. } => {
247256
let op = v.to_op(self.ecx())?;
248-
let idx = self.ecx().read_discriminant(op)?.1;
257+
let idx = self.read_discriminant(op)?;
249258
let inner = v.project_downcast(self.ecx(), idx)?;
250259
trace!("walk_value: variant layout: {:#?}", inner.layout());
251260
// recurse with the inner type

src/test/ui/consts/const-eval/double_check2.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | / static FOO: (&Foo, &Bar) = unsafe {(
55
LL | | Union { u8: &BAR }.foo,
66
LL | | Union { u8: &BAR }.bar,
77
LL | | )};
8-
| |___^ type validation failed: encountered 0x05 at .1.<deref>, but expected a valid enum tag
8+
| |___^ type validation failed: encountered 0x05 at .1.<deref>.<enum-tag>, but expected a valid enum tag
99
|
1010
= 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.
1111

src/test/ui/consts/const-eval/ub-enum.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: it is undefined behavior to use this value
22
--> $DIR/ub-enum.rs:24:1
33
|
44
LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001, but expected a valid enum tag
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000001 at .<enum-tag>, but expected a valid enum tag
66
|
77
= 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.
88

@@ -26,7 +26,7 @@ error[E0080]: it is undefined behavior to use this value
2626
--> $DIR/ub-enum.rs:42:1
2727
|
2828
LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) };
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000, but expected a valid enum tag
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x00000000 at .<enum-tag>, but expected a valid enum tag
3030
|
3131
= 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.
3232

0 commit comments

Comments
 (0)