value.to_bool(),
self.path,
err_ub!(InvalidBool(..)) | err_ub!(InvalidUninitBytes(None)) =>
- { "{}", value } expected { "a boolean" },
+ { "{:x}", value } expected { "a boolean" },
);
Ok(true)
}
value.to_char(),
self.path,
err_ub!(InvalidChar(..)) | err_ub!(InvalidUninitBytes(None)) =>
- { "{}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" },
+ { "{:x}", value } expected { "a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`)" },
);
Ok(true)
}
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
if !is_bits {
throw_validation_failure!(self.path,
- { "{}", value } expected { "initialized plain (non-pointer) bytes" }
+ { "{:x}", value } expected { "initialized plain (non-pointer) bytes" }
)
}
}
}
ty::FnPtr(_sig) => {
let value = try_validation!(
- self.ecx.read_immediate(value),
+ self.ecx.read_scalar(value).and_then(|v| v.check_init()),
self.path,
err_unsup!(ReadPointerAsBytes) => { "part of a pointer" } expected { "a proper pointer or integer value" },
+ err_ub!(InvalidUninitBytes(None)) => { "uninitialized bytes" } expected { "a proper pointer or integer value" },
);
- // Make sure we print a `ScalarMaybeUninit` (and not an `ImmTy`) in the error
- // message below.
- let value = value.to_scalar_or_uninit();
- let _fn = try_validation!(
- value.check_init().and_then(|ptr| self.ecx.memory.get_fn(self.ecx.scalar_to_ptr(ptr))),
- self.path,
- err_ub!(DanglingIntPointer(..)) |
- err_ub!(InvalidFunctionPointer(..)) |
- err_ub!(InvalidUninitBytes(None)) =>
- { "{}", value } expected { "a function pointer" },
- );
- // FIXME: Check if the signature matches
+
+ // If we check references recursively, also check that this points to a function.
+ if let Some(_) = self.ref_tracking {
+ let ptr = self.ecx.scalar_to_ptr(value);
+ let _fn = try_validation!(
+ self.ecx.memory.get_fn(ptr),
+ self.path,
+ err_ub!(DanglingIntPointer(0, _)) =>
+ { "a null function pointer" },
+ err_ub!(DanglingIntPointer(..)) |
+ err_ub!(InvalidFunctionPointer(..)) =>
+ { "{:x}", value } expected { "a function pointer" },
+ );
+ // FIXME: Check if the signature matches
+ } else {
+ // Otherwise (for standalone Miri), we have to still check it to be non-null.
+ if self.ecx.scalar_may_be_null(value) {
+ throw_validation_failure!(self.path, { "a null function pointer" });
+ }
+ }
Ok(true)
}
ty::Never => throw_validation_failure!(self.path, { "a value of the never type `!`" }),
let value = try_validation!(
value.check_init(),
self.path,
- err_ub!(InvalidUninitBytes(None)) => { "{}", value }
+ err_ub!(InvalidUninitBytes(None)) => { "{:x}", value }
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 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) {
+ if self.ecx.scalar_may_be_null(value) {
throw_validation_failure!(self.path,
{ "a potentially null pointer" }
expected {
this.ecx.read_discriminant(op),
this.path,
err_ub!(InvalidTag(val)) =>
- { "{}", val } expected { "a valid enum tag" },
+ { "{:x}", val } expected { "a valid enum tag" },
err_ub!(InvalidUninitBytes(None)) =>
{ "uninitialized bytes" } expected { "a valid enum tag" },
err_unsup!(ReadPointerAsBytes) =>
fn visit_value(&mut self, op: &OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
trace!("visit_value: {:?}, {:?}", *op, op.layout);
- // Check primitive types -- the leafs of our recursive descend.
+ // Check primitive types -- the leaves of our recursive descent.
if self.try_visit_primitive(op)? {
return Ok(());
}
// to reject those pointers, we just do not have the machinery to
// talk about parts of a pointer.
// We also accept uninit, for consistency with the slow path.
- let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? {
- Some(a) => a,
- None => {
- // Size 0, nothing more to check.
- return Ok(());
- }
+ let Some(alloc) = self.ecx.memory.get(mplace.ptr, size, mplace.align)? else {
+ // Size 0, nothing more to check.
+ return Ok(());
};
let allow_uninit_and_ptr = !M::enforce_number_validity(self.ecx);