Skip to content

Commit 8c0f601

Browse files
committed
fix Miri discriminant load/store when overflows are involved
1 parent 3e3e06d commit 8c0f601

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-17
lines changed

src/librustc_mir/interpret/operand.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -609,15 +609,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
609609
) -> InterpResult<'tcx, (u128, VariantIdx)> {
610610
trace!("read_discriminant_value {:#?}", rval.layout);
611611

612-
let (discr_kind, discr_index) = match rval.layout.variants {
612+
let (discr_layout, discr_kind, discr_index) = match rval.layout.variants {
613613
layout::Variants::Single { index } => {
614614
let discr_val = rval.layout.ty.discriminant_for_variant(*self.tcx, index).map_or(
615615
index.as_u32() as u128,
616616
|discr| discr.val);
617617
return Ok((discr_val, index));
618618
}
619-
layout::Variants::Multiple { ref discr_kind, discr_index, .. } =>
620-
(discr_kind, discr_index),
619+
layout::Variants::Multiple {
620+
discr: ref discr_layout,
621+
ref discr_kind,
622+
discr_index,
623+
..
624+
} =>
625+
(discr_layout, discr_kind, discr_index),
621626
};
622627

623628
// read raw discriminant value
@@ -634,7 +639,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
634639
.map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?;
635640
let real_discr = if discr_val.layout.ty.is_signed() {
636641
// going from layout tag type to typeck discriminant type
637-
// requires first sign extending with the layout discriminant
642+
// requires first sign extending with the discriminant layout
638643
let sexted = sign_extend(bits_discr, discr_val.layout.size) as i128;
639644
// and then zeroing with the typeck discriminant type
640645
let discr_ty = rval.layout.ty
@@ -682,8 +687,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
682687
(dataful_variant.as_u32() as u128, dataful_variant)
683688
},
684689
Ok(raw_discr) => {
685-
let adjusted_discr = raw_discr.wrapping_sub(niche_start)
686-
.wrapping_add(variants_start);
690+
// FIXME: WTF, some discriminants don't have integer type.
691+
use layout::Primitive;
692+
let discr_layout = self.layout_of(match discr_layout.value {
693+
Primitive::Int(int, signed) => int.to_ty(*self.tcx, signed),
694+
Primitive::Pointer => self.tcx.types.usize,
695+
Primitive::Float(..) => bug!("there are no float discriminants"),
696+
})?;
697+
let discr_val = ImmTy::from_uint(raw_discr, discr_layout);
698+
// We need to use machine arithmetic.
699+
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
700+
let variants_start_val = ImmTy::from_uint(variants_start, discr_layout);
701+
let adjusted_discr = self.binary_op(
702+
mir::BinOp::Sub,
703+
discr_val,
704+
niche_start_val,
705+
)?;
706+
let adjusted_discr = self.binary_op(
707+
mir::BinOp::Add,
708+
adjusted_discr,
709+
variants_start_val,
710+
)?;
711+
let adjusted_discr = adjusted_discr
712+
.to_scalar()?
713+
.assert_bits(discr_val.layout.size);
714+
// Check if this is in the range that indicates an actual discriminant.
687715
if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
688716
let index = adjusted_discr as usize;
689717
assert_eq!(index as u128, adjusted_discr);

src/librustc_mir/interpret/place.rs

+31-11
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use std::hash::Hash;
88
use rustc::mir;
99
use rustc::mir::interpret::truncate;
1010
use rustc::ty::{self, Ty};
11-
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
11+
use rustc::ty::layout::{
12+
self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, IntegerExt
13+
};
1214
use rustc::ty::TypeFoldable;
1315

1416
use super::{
@@ -1027,7 +1029,7 @@ where
10271029
}
10281030
layout::Variants::Multiple {
10291031
discr_kind: layout::DiscriminantKind::Tag,
1030-
ref discr,
1032+
discr: ref discr_layout,
10311033
discr_index,
10321034
..
10331035
} => {
@@ -1038,7 +1040,7 @@ where
10381040
// raw discriminants for enums are isize or bigger during
10391041
// their computation, but the in-memory tag is the smallest possible
10401042
// representation
1041-
let size = discr.value.size(self);
1043+
let size = discr_layout.value.size(self);
10421044
let discr_val = truncate(discr_val, size);
10431045

10441046
let discr_dest = self.place_field(dest, discr_index as u64)?;
@@ -1050,22 +1052,40 @@ where
10501052
ref niche_variants,
10511053
niche_start,
10521054
},
1055+
discr: ref discr_layout,
10531056
discr_index,
10541057
..
10551058
} => {
10561059
assert!(
10571060
variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
10581061
);
10591062
if variant_index != dataful_variant {
1060-
let niche_dest =
1061-
self.place_field(dest, discr_index as u64)?;
1062-
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
1063-
let niche_value = (niche_value as u128)
1064-
.wrapping_add(niche_start);
1065-
self.write_scalar(
1066-
Scalar::from_uint(niche_value, niche_dest.layout.size),
1067-
niche_dest
1063+
// FIXME: WTF, some discriminants don't have integer type.
1064+
use layout::Primitive;
1065+
let discr_layout = self.layout_of(match discr_layout.value {
1066+
Primitive::Int(int, signed) => int.to_ty(*self.tcx, signed),
1067+
Primitive::Pointer => self.tcx.types.usize,
1068+
Primitive::Float(..) => bug!("there are no float discriminants"),
1069+
})?;
1070+
1071+
// We need to use machine arithmetic.
1072+
let variants_start = niche_variants.start().as_u32();
1073+
let variants_start_val = ImmTy::from_uint(variants_start, discr_layout);
1074+
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
1075+
let variant_index_val = ImmTy::from_uint(variant_index.as_u32(), discr_layout);
1076+
let niche_val = self.binary_op(
1077+
mir::BinOp::Sub,
1078+
variant_index_val,
1079+
variants_start_val,
1080+
)?;
1081+
let niche_val = self.binary_op(
1082+
mir::BinOp::Add,
1083+
niche_val,
1084+
niche_start_val,
10681085
)?;
1086+
// Write result.
1087+
let niche_dest = self.place_field(dest, discr_index as u64)?;
1088+
self.write_immediate(*niche_val, niche_dest)?;
10691089
}
10701090
}
10711091
}

0 commit comments

Comments
 (0)