fix Miri discriminant load/store when overflows are involved
This commit is contained in:
parent
3e3e06dfdd
commit
8c0f601105
2 changed files with 65 additions and 17 deletions
|
|
@ -609,15 +609,20 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
) -> InterpResult<'tcx, (u128, VariantIdx)> {
|
||||
trace!("read_discriminant_value {:#?}", rval.layout);
|
||||
|
||||
let (discr_kind, discr_index) = match rval.layout.variants {
|
||||
let (discr_layout, discr_kind, discr_index) = match rval.layout.variants {
|
||||
layout::Variants::Single { index } => {
|
||||
let discr_val = rval.layout.ty.discriminant_for_variant(*self.tcx, index).map_or(
|
||||
index.as_u32() as u128,
|
||||
|discr| discr.val);
|
||||
return Ok((discr_val, index));
|
||||
}
|
||||
layout::Variants::Multiple { ref discr_kind, discr_index, .. } =>
|
||||
(discr_kind, discr_index),
|
||||
layout::Variants::Multiple {
|
||||
discr: ref discr_layout,
|
||||
ref discr_kind,
|
||||
discr_index,
|
||||
..
|
||||
} =>
|
||||
(discr_layout, discr_kind, discr_index),
|
||||
};
|
||||
|
||||
// read raw discriminant value
|
||||
|
|
@ -634,7 +639,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
.map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?;
|
||||
let real_discr = if discr_val.layout.ty.is_signed() {
|
||||
// going from layout tag type to typeck discriminant type
|
||||
// requires first sign extending with the layout discriminant
|
||||
// requires first sign extending with the discriminant layout
|
||||
let sexted = sign_extend(bits_discr, discr_val.layout.size) as i128;
|
||||
// and then zeroing with the typeck discriminant type
|
||||
let discr_ty = rval.layout.ty
|
||||
|
|
@ -682,8 +687,31 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
(dataful_variant.as_u32() as u128, dataful_variant)
|
||||
},
|
||||
Ok(raw_discr) => {
|
||||
let adjusted_discr = raw_discr.wrapping_sub(niche_start)
|
||||
.wrapping_add(variants_start);
|
||||
// FIXME: WTF, some discriminants don't have integer type.
|
||||
use layout::Primitive;
|
||||
let discr_layout = self.layout_of(match discr_layout.value {
|
||||
Primitive::Int(int, signed) => int.to_ty(*self.tcx, signed),
|
||||
Primitive::Pointer => self.tcx.types.usize,
|
||||
Primitive::Float(..) => bug!("there are no float discriminants"),
|
||||
})?;
|
||||
let discr_val = ImmTy::from_uint(raw_discr, discr_layout);
|
||||
// We need to use machine arithmetic.
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
|
||||
let variants_start_val = ImmTy::from_uint(variants_start, discr_layout);
|
||||
let adjusted_discr = self.binary_op(
|
||||
mir::BinOp::Sub,
|
||||
discr_val,
|
||||
niche_start_val,
|
||||
)?;
|
||||
let adjusted_discr = self.binary_op(
|
||||
mir::BinOp::Add,
|
||||
adjusted_discr,
|
||||
variants_start_val,
|
||||
)?;
|
||||
let adjusted_discr = adjusted_discr
|
||||
.to_scalar()?
|
||||
.assert_bits(discr_val.layout.size);
|
||||
// Check if this is in the range that indicates an actual discriminant.
|
||||
if variants_start <= adjusted_discr && adjusted_discr <= variants_end {
|
||||
let index = adjusted_discr as usize;
|
||||
assert_eq!(index as u128, adjusted_discr);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use std::hash::Hash;
|
|||
use rustc::mir;
|
||||
use rustc::mir::interpret::truncate;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx};
|
||||
use rustc::ty::layout::{
|
||||
self, Size, Align, LayoutOf, TyLayout, HasDataLayout, VariantIdx, IntegerExt
|
||||
};
|
||||
use rustc::ty::TypeFoldable;
|
||||
|
||||
use super::{
|
||||
|
|
@ -1027,7 +1029,7 @@ where
|
|||
}
|
||||
layout::Variants::Multiple {
|
||||
discr_kind: layout::DiscriminantKind::Tag,
|
||||
ref discr,
|
||||
discr: ref discr_layout,
|
||||
discr_index,
|
||||
..
|
||||
} => {
|
||||
|
|
@ -1038,7 +1040,7 @@ where
|
|||
// raw discriminants for enums are isize or bigger during
|
||||
// their computation, but the in-memory tag is the smallest possible
|
||||
// representation
|
||||
let size = discr.value.size(self);
|
||||
let size = discr_layout.value.size(self);
|
||||
let discr_val = truncate(discr_val, size);
|
||||
|
||||
let discr_dest = self.place_field(dest, discr_index as u64)?;
|
||||
|
|
@ -1050,6 +1052,7 @@ where
|
|||
ref niche_variants,
|
||||
niche_start,
|
||||
},
|
||||
discr: ref discr_layout,
|
||||
discr_index,
|
||||
..
|
||||
} => {
|
||||
|
|
@ -1057,15 +1060,32 @@ where
|
|||
variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
|
||||
);
|
||||
if variant_index != dataful_variant {
|
||||
let niche_dest =
|
||||
self.place_field(dest, discr_index as u64)?;
|
||||
let niche_value = variant_index.as_u32() - niche_variants.start().as_u32();
|
||||
let niche_value = (niche_value as u128)
|
||||
.wrapping_add(niche_start);
|
||||
self.write_scalar(
|
||||
Scalar::from_uint(niche_value, niche_dest.layout.size),
|
||||
niche_dest
|
||||
// FIXME: WTF, some discriminants don't have integer type.
|
||||
use layout::Primitive;
|
||||
let discr_layout = self.layout_of(match discr_layout.value {
|
||||
Primitive::Int(int, signed) => int.to_ty(*self.tcx, signed),
|
||||
Primitive::Pointer => self.tcx.types.usize,
|
||||
Primitive::Float(..) => bug!("there are no float discriminants"),
|
||||
})?;
|
||||
|
||||
// We need to use machine arithmetic.
|
||||
let variants_start = niche_variants.start().as_u32();
|
||||
let variants_start_val = ImmTy::from_uint(variants_start, discr_layout);
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout);
|
||||
let variant_index_val = ImmTy::from_uint(variant_index.as_u32(), discr_layout);
|
||||
let niche_val = self.binary_op(
|
||||
mir::BinOp::Sub,
|
||||
variant_index_val,
|
||||
variants_start_val,
|
||||
)?;
|
||||
let niche_val = self.binary_op(
|
||||
mir::BinOp::Add,
|
||||
niche_val,
|
||||
niche_start_val,
|
||||
)?;
|
||||
// Write result.
|
||||
let niche_dest = self.place_field(dest, discr_index as u64)?;
|
||||
self.write_immediate(*niche_val, niche_dest)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue