1
Fork 0

Add methods for checking for full ranges to Scalar and WrappingRange

Move *_max methods back to util

change to inline instead of inline(always)

Remove valid_range_exclusive from scalar
Use WrappingRange instead

implement always_valid_for in a safer way

Fix accidental edit
This commit is contained in:
Andreas Liljeqvist 2021-08-25 15:21:45 +02:00
parent c5cbf7852a
commit 05cd48b008
7 changed files with 41 additions and 56 deletions

View file

@ -620,38 +620,36 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
op: &OpTy<'tcx, M::PointerTag>,
scalar_layout: &ScalarAbi,
) -> InterpResult<'tcx> {
let value = self.read_scalar(op)?;
let valid_range = scalar_layout.valid_range.clone();
let WrappingRange { start: lo, end: hi } = valid_range;
// Determine the allowed range
// `max_hi` is as big as the size fits
let max_hi = u128::MAX >> (128 - op.layout.size.bits());
assert!(hi <= max_hi);
// We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
if scalar_layout.valid_range.is_full_for(op.layout.size) {
// Nothing to check
return Ok(());
}
// At least one value is excluded. Get the bits.
// At least one value is excluded.
let valid_range = scalar_layout.valid_range.clone();
let WrappingRange { start, end } = valid_range;
let max_value = u128::MAX >> (128 - op.layout.size.bits());
assert!(end <= max_value);
// Determine the allowed range
let value = self.read_scalar(op)?;
let value = try_validation!(
value.check_init(),
self.path,
err_ub!(InvalidUninitBytes(None)) => { "{}", value }
expected { "something {}", wrapping_range_format(valid_range, max_hi) },
expected { "something {}", wrapping_range_format(valid_range, max_value) },
);
let bits = match value.try_to_int() {
Err(_) => {
// So this is a pointer then, and casting to an int failed.
// Can only happen during CTFE.
let ptr = self.ecx.scalar_to_ptr(value);
if lo == 1 && hi == max_hi {
if start == 1 && end == max_value {
// Only null is the niche. So make sure the ptr is NOT null.
if self.ecx.memory.ptr_may_be_null(ptr) {
throw_validation_failure!(self.path,
{ "a potentially null pointer" }
expected {
"something that cannot possibly fail to be {}",
wrapping_range_format(valid_range, max_hi)
wrapping_range_format(valid_range, max_value)
}
)
}
@ -663,7 +661,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
{ "a pointer" }
expected {
"something that cannot possibly fail to be {}",
wrapping_range_format(valid_range, max_hi)
wrapping_range_format(valid_range, max_value)
}
)
}
@ -676,7 +674,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
} else {
throw_validation_failure!(self.path,
{ "{}", bits }
expected { "something {}", wrapping_range_format(valid_range, max_hi) }
expected { "something {}", wrapping_range_format(valid_range, max_value) }
)
}
}