Auto merge of #1219 - RalfJung:error-cleanup, r=RalfJung
rustup for error reform This is the Miri side of https://github.com/rust-lang/rust/pull/69839.
This commit is contained in:
commit
0ff05c4cfe
77 changed files with 185 additions and 207 deletions
|
|
@ -1 +1 @@
|
|||
660326e9791d5caf3186b14521498c2584a494ab
|
||||
57e1da59cd0761330b4ea8d47b16340a78eeafa9
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use crate::*;
|
|||
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
|
||||
/// Gets an instance for a path.
|
||||
fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> {
|
||||
fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option<DefId> {
|
||||
tcx.crates()
|
||||
.iter()
|
||||
.find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0])
|
||||
|
|
@ -41,19 +41,47 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc
|
|||
}
|
||||
None
|
||||
})
|
||||
.ok_or_else(|| {
|
||||
let path = path.iter().map(|&s| s.to_owned()).collect();
|
||||
err_unsup!(PathNotFound(path)).into()
|
||||
})
|
||||
}
|
||||
|
||||
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
|
||||
/// Gets an instance for a path.
|
||||
fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> {
|
||||
Ok(ty::Instance::mono(
|
||||
self.eval_context_ref().tcx.tcx,
|
||||
resolve_did(self.eval_context_ref().tcx.tcx, path)?,
|
||||
))
|
||||
fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> {
|
||||
let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)
|
||||
.unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path));
|
||||
ty::Instance::mono(self.eval_context_ref().tcx.tcx, did)
|
||||
}
|
||||
|
||||
/// Evaluates the scalar at the specified path. Returns Some(val)
|
||||
/// if the path could be resolved, and None otherwise
|
||||
fn eval_path_scalar(
|
||||
&mut self,
|
||||
path: &[&str],
|
||||
) -> InterpResult<'tcx, ScalarMaybeUndef<Tag>> {
|
||||
let this = self.eval_context_mut();
|
||||
let instance = this.resolve_path(path);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let const_val = this.const_eval_raw(cid)?;
|
||||
let const_val = this.read_scalar(const_val.into())?;
|
||||
return Ok(const_val);
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as a `Scalar`.
|
||||
fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
|
||||
self.eval_context_mut()
|
||||
.eval_path_scalar(&["libc", name])?
|
||||
.not_undef()
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as an `i32`.
|
||||
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
|
||||
self.eval_libc(name)?.to_i32()
|
||||
}
|
||||
|
||||
/// Helper function to get the `TyLayout` of a `libc` type
|
||||
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> {
|
||||
let this = self.eval_context_mut();
|
||||
let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx);
|
||||
this.layout_of(ty)
|
||||
}
|
||||
|
||||
/// Write a 0 of the appropriate size to `dest`.
|
||||
|
|
@ -98,7 +126,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
if this.machine.communicate {
|
||||
// Fill the buffer using the host's rng.
|
||||
getrandom::getrandom(&mut data)
|
||||
.map_err(|err| err_unsup_format!("getrandom failed: {}", err))?;
|
||||
.map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?;
|
||||
} else {
|
||||
let rng = this.memory.extra.rng.get_mut();
|
||||
rng.fill_bytes(&mut data);
|
||||
|
|
@ -313,26 +341,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
}
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as a `Scalar`.
|
||||
fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar<Tag>> {
|
||||
self.eval_context_mut()
|
||||
.eval_path_scalar(&["libc", name])?
|
||||
.ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name))?
|
||||
.not_undef()
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as an `i32`.
|
||||
fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> {
|
||||
self.eval_libc(name)?.to_i32()
|
||||
}
|
||||
|
||||
/// Helper function to get the `TyLayout` of a `libc` type
|
||||
fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> {
|
||||
let this = self.eval_context_mut();
|
||||
let ty = this.resolve_path(&["libc", name])?.monomorphic_ty(*this.tcx);
|
||||
this.layout_of(ty)
|
||||
}
|
||||
|
||||
// Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack
|
||||
// different values into a struct.
|
||||
fn write_packed_immediates(
|
||||
|
|
@ -360,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> {
|
||||
if !self.eval_context_ref().machine.communicate {
|
||||
throw_unsup_format!(
|
||||
"`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.",
|
||||
"`{}` not available when isolation is enabled (pass the flag `-Zmiri-disable-isolation` to disable isolation)",
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
|
@ -416,13 +424,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
AlreadyExists => "EEXIST",
|
||||
WouldBlock => "EWOULDBLOCK",
|
||||
_ => {
|
||||
throw_unsup_format!("The {} error cannot be transformed into a raw os error", e)
|
||||
throw_unsup_format!("io error {} cannot be transformed into a raw os error", e)
|
||||
}
|
||||
})?
|
||||
} else {
|
||||
// FIXME: we have to implement the Windows equivalent of this.
|
||||
throw_unsup_format!(
|
||||
"Setting the last OS error from an io::Error is unsupported for {}.",
|
||||
"setting the last OS error from an io::Error is unsupported for {}.",
|
||||
target.target_os
|
||||
)
|
||||
};
|
||||
|
|
@ -531,7 +539,7 @@ pub fn immty_from_int_checked<'tcx>(
|
|||
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
|
||||
let int = int.into();
|
||||
Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| {
|
||||
err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits())
|
||||
err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits())
|
||||
})?)
|
||||
}
|
||||
|
||||
|
|
@ -541,6 +549,6 @@ pub fn immty_from_uint_checked<'tcx>(
|
|||
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
|
||||
let int = int.into();
|
||||
Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| {
|
||||
err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits())
|
||||
err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits())
|
||||
})?)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,10 +43,6 @@ impl<'mir, 'tcx> GlobalState {
|
|||
int: u64,
|
||||
memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>,
|
||||
) -> InterpResult<'tcx, Pointer<Tag>> {
|
||||
if int == 0 {
|
||||
throw_unsup!(InvalidNullPointerUsage);
|
||||
}
|
||||
|
||||
let global_state = memory.extra.intptrcast.borrow();
|
||||
let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr);
|
||||
|
||||
|
|
@ -57,7 +53,7 @@ impl<'mir, 'tcx> GlobalState {
|
|||
// zero. The pointer is untagged because it was created from a cast
|
||||
Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)
|
||||
}
|
||||
Err(0) => throw_unsup!(DanglingPointerDeref),
|
||||
Err(0) => throw_ub!(InvalidIntPointerUsage(int)),
|
||||
Err(pos) => {
|
||||
// This is the largest of the adresses smaller than `int`,
|
||||
// i.e. the greatest lower bound (glb)
|
||||
|
|
@ -69,7 +65,7 @@ impl<'mir, 'tcx> GlobalState {
|
|||
// This pointer is untagged because it was created from a cast
|
||||
Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)
|
||||
} else {
|
||||
throw_unsup!(DanglingPointerDeref)
|
||||
throw_ub!(InvalidIntPointerUsage(int))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ impl Dlsym {
|
|||
Ok(match name {
|
||||
"getentropy" => Some(GetEntropy),
|
||||
"__pthread_get_minstack" => None,
|
||||
_ => throw_unsup_format!("Unsupported dlsym: {}", name),
|
||||
_ => throw_unsup_format!("unsupported dlsym: {}", name),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
.expect("No panic runtime found!");
|
||||
let panic_runtime = tcx.crate_name(*panic_runtime);
|
||||
let start_panic_instance =
|
||||
this.resolve_path(&[&*panic_runtime.as_str(), link_name])?;
|
||||
this.resolve_path(&[&*panic_runtime.as_str(), link_name]);
|
||||
return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?));
|
||||
}
|
||||
_ => {}
|
||||
|
|
@ -222,12 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"__rust_alloc" => {
|
||||
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
|
||||
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
|
||||
if size == 0 {
|
||||
throw_unsup!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
Self::check_alloc_request(size, align)?;
|
||||
let ptr = this.memory.allocate(
|
||||
Size::from_bytes(size),
|
||||
Align::from_bytes(align).unwrap(),
|
||||
|
|
@ -238,12 +233,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
"__rust_alloc_zeroed" => {
|
||||
let size = this.read_scalar(args[0])?.to_machine_usize(this)?;
|
||||
let align = this.read_scalar(args[1])?.to_machine_usize(this)?;
|
||||
if size == 0 {
|
||||
throw_unsup!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
Self::check_alloc_request(size, align)?;
|
||||
let ptr = this.memory.allocate(
|
||||
Size::from_bytes(size),
|
||||
Align::from_bytes(align).unwrap(),
|
||||
|
|
@ -257,12 +247,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let ptr = this.read_scalar(args[0])?.not_undef()?;
|
||||
let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?;
|
||||
let align = this.read_scalar(args[2])?.to_machine_usize(this)?;
|
||||
if old_size == 0 {
|
||||
throw_unsup!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
// No need to check old_size/align; we anyway check that they match the allocation.
|
||||
let ptr = this.force_ptr(ptr)?;
|
||||
this.memory.deallocate(
|
||||
ptr,
|
||||
|
|
@ -274,12 +259,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?;
|
||||
let align = this.read_scalar(args[2])?.to_machine_usize(this)?;
|
||||
let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?;
|
||||
if old_size == 0 || new_size == 0 {
|
||||
throw_unsup!(HeapAllocZeroBytes);
|
||||
}
|
||||
if !align.is_power_of_two() {
|
||||
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
}
|
||||
Self::check_alloc_request(new_size, align)?;
|
||||
// No need to check old_size; we anyway check that they match the allocation.
|
||||
let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?;
|
||||
let align = Align::from_bytes(align).unwrap();
|
||||
let new_ptr = this.memory.reallocate(
|
||||
|
|
@ -455,26 +436,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
_ => match this.tcx.sess.target.target.target_os.as_str() {
|
||||
"linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
|
||||
"windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret),
|
||||
target => throw_unsup_format!("The {} target platform is not supported", target),
|
||||
target => throw_unsup_format!("the {} target platform is not supported", target),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Evaluates the scalar at the specified path. Returns Some(val)
|
||||
/// if the path could be resolved, and None otherwise
|
||||
fn eval_path_scalar(
|
||||
&mut self,
|
||||
path: &[&str],
|
||||
) -> InterpResult<'tcx, Option<ScalarMaybeUndef<Tag>>> {
|
||||
let this = self.eval_context_mut();
|
||||
if let Ok(instance) = this.resolve_path(path) {
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
let const_val = this.const_eval_raw(cid)?;
|
||||
let const_val = this.read_scalar(const_val.into())?;
|
||||
return Ok(Some(const_val));
|
||||
/// Check some basic requirements for this allocation request:
|
||||
/// non-zero size, power-of-two alignment.
|
||||
fn check_alloc_request(size: u64, align: u64) -> InterpResult<'tcx> {
|
||||
if size == 0 {
|
||||
throw_ub_format!("creating allocation with size 0");
|
||||
}
|
||||
return Ok(None);
|
||||
if !align.is_power_of_two() {
|
||||
throw_ub_format!("creating allocation with non-power-of-two alignment {}", align);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let size = this.read_scalar(args[2])?.to_machine_usize(this)?;
|
||||
// Align must be power of 2, and also at least ptr-sized (POSIX rules).
|
||||
if !align.is_power_of_two() {
|
||||
throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align));
|
||||
throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align);
|
||||
}
|
||||
if align < this.pointer_size().bytes() {
|
||||
throw_ub_format!(
|
||||
|
|
@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
};
|
||||
|
||||
// Figure out how large a pthread TLS key actually is.
|
||||
// This is `libc::pthread_key_t`.
|
||||
// To this end, deref the argument type. This is `libc::pthread_key_t`.
|
||||
let key_type = args[0].layout.ty
|
||||
.builtin_deref(true)
|
||||
.ok_or_else(|| err_ub_format!(
|
||||
|
|
@ -195,12 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let key_layout = this.layout_of(key_type)?;
|
||||
|
||||
// Create key and write it into the memory where `key_ptr` wants it.
|
||||
let key = this.machine.tls.create_tls_key(dtor) as u128;
|
||||
if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128)
|
||||
{
|
||||
throw_unsup!(OutOfTls);
|
||||
}
|
||||
|
||||
let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?;
|
||||
this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?;
|
||||
|
||||
// Return success (`0`).
|
||||
|
|
@ -294,28 +289,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
trace!("sysconf() called with name {}", name);
|
||||
// TODO: Cache the sysconf integers via Miri's global cache.
|
||||
let paths = &[
|
||||
(&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)),
|
||||
(&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)),
|
||||
(
|
||||
&["libc", "_SC_NPROCESSORS_ONLN"],
|
||||
Scalar::from_int(NUM_CPUS, dest.layout.size),
|
||||
),
|
||||
let sysconfs = &[
|
||||
("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)),
|
||||
("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)),
|
||||
("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)),
|
||||
];
|
||||
let mut result = None;
|
||||
for &(path, path_value) in paths {
|
||||
if let Some(val) = this.eval_path_scalar(path)? {
|
||||
let val = val.to_i32()?;
|
||||
if val == name {
|
||||
result = Some(path_value);
|
||||
break;
|
||||
}
|
||||
for &(sysconf_name, value) in sysconfs {
|
||||
let sysconf_name = this.eval_libc_i32(sysconf_name)?;
|
||||
if sysconf_name == name {
|
||||
result = Some(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(result) = result {
|
||||
this.write_scalar(result, dest)?;
|
||||
} else {
|
||||
throw_unsup_format!("Unimplemented sysconf name: {}", name)
|
||||
throw_unsup_format!("unimplemented sysconf name: {}", name)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,13 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
|
||||
"syscall" => {
|
||||
let sys_getrandom = this
|
||||
.eval_path_scalar(&["libc", "SYS_getrandom"])?
|
||||
.expect("Failed to get libc::SYS_getrandom")
|
||||
.eval_libc("SYS_getrandom")?
|
||||
.to_machine_usize(this)?;
|
||||
|
||||
let sys_statx = this
|
||||
.eval_path_scalar(&["libc", "SYS_statx"])?
|
||||
.expect("Failed to get libc::SYS_statx")
|
||||
.eval_libc("SYS_statx")?
|
||||
.to_machine_usize(this)?;
|
||||
|
||||
match this.read_scalar(args[0])?.to_machine_usize(this)? {
|
||||
|
|
|
|||
|
|
@ -154,14 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// This just creates a key; Windows does not natively support TLS destructors.
|
||||
|
||||
// Create key and return it.
|
||||
let key = this.machine.tls.create_tls_key(None) as u128;
|
||||
|
||||
// Figure out how large a TLS key actually is. This is `c::DWORD`.
|
||||
if dest.layout.size.bits() < 128
|
||||
&& key >= (1u128 << dest.layout.size.bits() as u128)
|
||||
{
|
||||
throw_unsup!(OutOfTls);
|
||||
}
|
||||
let key = this.machine.tls.create_tls_key(None, dest.layout.size)?;
|
||||
this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?;
|
||||
}
|
||||
"TlsGetValue" => {
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, '
|
|||
}
|
||||
Err(e) => return match e.raw_os_error() {
|
||||
Some(error) => Ok(error),
|
||||
None => throw_unsup_format!("The error {} couldn't be converted to a return value", e),
|
||||
None => throw_unsup_format!("the error {} couldn't be converted to a return value", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// windows. We need to check that in fact the access mode flags for the current platform
|
||||
// only use these two bits, otherwise we are in an unsupported platform and should error.
|
||||
if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
|
||||
throw_unsup_format!("Access mode flags on this platform are unsupported");
|
||||
throw_unsup_format!("access mode flags on this platform are unsupported");
|
||||
}
|
||||
let mut writable = true;
|
||||
|
||||
|
|
@ -276,7 +276,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
} else if access_mode == o_rdwr {
|
||||
options.read(true).write(true);
|
||||
} else {
|
||||
throw_unsup_format!("Unsupported access mode {:#x}", access_mode);
|
||||
throw_unsup_format!("unsupported access mode {:#x}", access_mode);
|
||||
}
|
||||
// We need to check that there aren't unsupported options in `flag`. For this we try to
|
||||
// reproduce the content of `flag` in the `mirror` variable using only the supported
|
||||
|
|
@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor,
|
||||
// thus they can share the same implementation here.
|
||||
if fd < MIN_NORMAL_FILE_FD {
|
||||
throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported")
|
||||
throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported")
|
||||
}
|
||||
let start_op = start_op.ok_or_else(|| {
|
||||
err_unsup_format!(
|
||||
|
|
@ -369,7 +369,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
});
|
||||
this.try_unwrap_io_result(fd_result)
|
||||
} else {
|
||||
throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
|
||||
throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// FIXME: This long path is required because `libc::statx` is an struct and also a
|
||||
// function and `resolve_path` is returning the latter.
|
||||
let statx_ty = this
|
||||
.resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])?
|
||||
.resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])
|
||||
.monomorphic_ty(*this.tcx);
|
||||
let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty);
|
||||
let statxbuf_layout = this.layout_of(statxbuf_ty)?;
|
||||
|
|
@ -655,13 +655,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// `flags` should be a `c_int` but the `syscall` function provides an `isize`.
|
||||
let flags: i32 =
|
||||
this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
|
||||
err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e)
|
||||
err_unsup_format!("failed to convert pointer sized operand to integer: {}", e)
|
||||
})?;
|
||||
let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0;
|
||||
// `dirfd` should be a `c_int` but the `syscall` function provides an `isize`.
|
||||
let dirfd: i32 =
|
||||
this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| {
|
||||
err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e)
|
||||
err_unsup_format!("failed to convert pointer sized operand to integer: {}", e)
|
||||
})?;
|
||||
// We only support:
|
||||
// * interpreting `path` as an absolute directory,
|
||||
|
|
@ -676,7 +676,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
(path.as_os_str().is_empty() && empty_path_flag)
|
||||
) {
|
||||
throw_unsup_format!(
|
||||
"Using statx is only supported with absolute paths, relative paths with the file \
|
||||
"using statx is only supported with absolute paths, relative paths with the file \
|
||||
descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \
|
||||
file descriptor"
|
||||
)
|
||||
|
|
@ -886,7 +886,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
|
||||
|
||||
let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| {
|
||||
err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir")
|
||||
err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir")
|
||||
})?;
|
||||
match dir_iter.next() {
|
||||
Some(Ok(dir_entry)) => {
|
||||
|
|
@ -913,7 +913,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
name_place.layout.size.bytes(),
|
||||
)?;
|
||||
if !name_fits {
|
||||
throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64");
|
||||
throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent64");
|
||||
}
|
||||
|
||||
let entry_place = this.deref_operand(entry_op)?;
|
||||
|
|
@ -953,7 +953,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// return positive error number on error
|
||||
Some(error) => Ok(error),
|
||||
None => {
|
||||
throw_unsup_format!("The error {} couldn't be converted to a return value", e)
|
||||
throw_unsup_format!("the error {} couldn't be converted to a return value", e)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -973,7 +973,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?;
|
||||
|
||||
let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| {
|
||||
err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir")
|
||||
err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir")
|
||||
})?;
|
||||
match dir_iter.next() {
|
||||
Some(Ok(dir_entry)) => {
|
||||
|
|
@ -1001,7 +1001,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
name_place.layout.size.bytes(),
|
||||
)?;
|
||||
if !name_fits {
|
||||
throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent");
|
||||
throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent");
|
||||
}
|
||||
|
||||
let entry_place = this.deref_operand(entry_op)?;
|
||||
|
|
@ -1042,7 +1042,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
|||
// return positive error number on error
|
||||
Some(error) => Ok(error),
|
||||
None => {
|
||||
throw_unsup_format!("The error {} couldn't be converted to a return value", e)
|
||||
throw_unsup_format!("the error {} couldn't be converted to a return value", e)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> {
|
|||
/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`.
|
||||
pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> {
|
||||
time.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into())
|
||||
.map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into())
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use rustc::{ty, ty::layout::HasDataLayout};
|
||||
use rustc::{ty, ty::layout::{Size, HasDataLayout}};
|
||||
use rustc_target::abi::LayoutOf;
|
||||
|
||||
use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag};
|
||||
|
|
@ -37,12 +37,18 @@ impl<'tcx> Default for TlsData<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TlsData<'tcx> {
|
||||
pub fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>) -> TlsKey {
|
||||
/// Generate a new TLS key with the given destructor.
|
||||
/// `max_size` determines the integer size the key has to fit in.
|
||||
pub fn create_tls_key(&mut self, dtor: Option<ty::Instance<'tcx>>, max_size: Size) -> InterpResult<'tcx, TlsKey> {
|
||||
let new_key = self.next_key;
|
||||
self.next_key += 1;
|
||||
self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none();
|
||||
trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor);
|
||||
new_key
|
||||
|
||||
if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) {
|
||||
throw_unsup_format!("we ran out of TLS key space");
|
||||
}
|
||||
Ok(new_key)
|
||||
}
|
||||
|
||||
pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> {
|
||||
|
|
@ -51,7 +57,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
trace!("TLS key {} removed", key);
|
||||
Ok(())
|
||||
}
|
||||
None => throw_unsup!(TlsOutOfBounds),
|
||||
None => throw_ub_format!("removing a non-existig TLS key: {}", key),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +71,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
trace!("TLS key {} loaded: {:?}", key, data);
|
||||
Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into()))
|
||||
}
|
||||
None => throw_unsup!(TlsOutOfBounds),
|
||||
None => throw_ub_format!("loading from a non-existing TLS key: {}", key),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +82,7 @@ impl<'tcx> TlsData<'tcx> {
|
|||
*data = new_data;
|
||||
Ok(())
|
||||
}
|
||||
None => throw_unsup!(TlsOutOfBounds),
|
||||
None => throw_ub_format!("storing to a non-existing TLS key: {}", key),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ fn main() {
|
|||
let x_ptr: *mut u8 = &mut x[0];
|
||||
let y_ptr = x_ptr as *mut u64;
|
||||
unsafe {
|
||||
*y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment
|
||||
*y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment
|
||||
}
|
||||
panic!("unreachable in miri");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ fn main() {
|
|||
let zptr = &z as *const _ as *const u64;
|
||||
unsafe {
|
||||
::std::intrinsics::atomic_load(zptr);
|
||||
//~^ ERROR tried to access memory with alignment 4, but alignment 8 is required
|
||||
//~^ ERROR accessing memory with alignment 4, but alignment 8 is required
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ fn main() {
|
|||
std::mem::transmute::<&Box<usize>, &fn(i32)>(&b)
|
||||
};
|
||||
|
||||
(*g)(42) //~ ERROR tried to treat a memory pointer as a function pointer
|
||||
(*g)(42) //~ ERROR it does not point to a function
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
fn main() {
|
||||
fn f() {}
|
||||
fn f() {} //~ ERROR calling a function with more arguments than it expected
|
||||
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn(), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR tried to call a function with incorrect number of arguments
|
||||
g(42)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ fn main() {
|
|||
std::mem::transmute::<fn((i32,i32)), fn(i32)>(f)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR tried to call a function with argument of type (i32, i32) passing data of type i32
|
||||
g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ fn main() {
|
|||
std::mem::transmute::<fn((i32,i32)), fn()>(f)
|
||||
};
|
||||
|
||||
g() //~ ERROR tried to call a function with incorrect number of arguments
|
||||
g() //~ ERROR calling a function with fewer arguments than it requires
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ fn main() {
|
|||
std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f)
|
||||
};
|
||||
|
||||
g(&42 as *const i32) //~ ERROR tried to call a function with argument of type *const [i32] passing data of type *const i32
|
||||
g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
fn main() {
|
||||
fn f() -> u32 { 42 }
|
||||
fn f() -> u32 { 42 } //~ ERROR calling a function with return type u32 passing return place of type ()
|
||||
|
||||
let g = unsafe {
|
||||
std::mem::transmute::<fn() -> u32, fn()>(f)
|
||||
};
|
||||
|
||||
g() //~ ERROR tried to call a function with return type u32 passing return place of type ()
|
||||
g()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ fn main() {
|
|||
std::mem::transmute::<usize, fn(i32)>(42)
|
||||
};
|
||||
|
||||
g(42) //~ ERROR dangling pointer was dereferenced
|
||||
g(42) //~ ERROR invalid use of 42 as a pointer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//error-pattern: tried to access memory with alignment 1, but alignment 2 is required
|
||||
//error-pattern: accessing memory with alignment 1, but alignment 2 is required
|
||||
#![feature(intrinsics)]
|
||||
|
||||
// Directly call intrinsic to avoid debug assertions in libstd
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@ fn main() {
|
|||
let b = Box::new(42);
|
||||
&*b as *const i32
|
||||
};
|
||||
let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced
|
||||
let x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ fn main() {
|
|||
let b = Box::new(42);
|
||||
&*b as *const i32 as *const ()
|
||||
};
|
||||
let _x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced
|
||||
let _x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
use alloc::alloc::Global;
|
||||
use std::alloc::{AllocRef, Layout};
|
||||
|
||||
// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1
|
||||
// error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
use alloc::alloc::Global;
|
||||
use std::alloc::{AllocRef, Layout};
|
||||
|
||||
// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
|
||||
// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
use alloc::alloc::Global;
|
||||
use std::alloc::{AllocRef, Layout};
|
||||
|
||||
// error-pattern: tried to deallocate dangling pointer
|
||||
// error-pattern: dereferenced after this allocation got freed
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
|
||||
fn main() {
|
||||
let x = 2usize as *const u32;
|
||||
let _y = unsafe { &*x as *const u32 }; //~ ERROR dangling pointer was dereferenced
|
||||
let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 2 as a pointer
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
fn main() {
|
||||
let x = (1, 13);
|
||||
let xptr = &x as *const _ as *const (i32, i32, i32);
|
||||
let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of allocation
|
||||
let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of alloc
|
||||
assert_eq!(val, 13);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ fn f() {}
|
|||
|
||||
fn main() {
|
||||
let x: u8 = unsafe {
|
||||
*std::mem::transmute::<fn(), *const u8>(f) //~ ERROR tried to dereference a function pointer
|
||||
*std::mem::transmute::<fn(), *const u8>(f) //~ ERROR contains a function
|
||||
};
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,5 +20,5 @@ fn main() {
|
|||
let pointer = get_environ();
|
||||
let _x = unsafe { *pointer };
|
||||
std::env::set_var("FOO", "BAR");
|
||||
let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced
|
||||
let _y = unsafe { *pointer }; //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ fn main() {
|
|||
let x = box 42;
|
||||
unsafe {
|
||||
let f = std::mem::transmute::<Box<i32>, fn()>(x);
|
||||
f() //~ ERROR tried to treat a memory pointer as a function pointer
|
||||
f() //~ ERROR function pointer but it does not point to a function
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ fn main() {
|
|||
let y : *mut u8 = unsafe { mem::transmute(x) };
|
||||
let y = y.wrapping_offset(1);
|
||||
let x : fn() = unsafe { mem::transmute(y) };
|
||||
x(); //~ ERROR tried to use a function pointer after offsetting it
|
||||
x(); //~ ERROR function pointer but it does not point to a function
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ fn firstn() -> impl Generator<Yield = u64, Return = ()> {
|
|||
let num = &mut num;
|
||||
|
||||
yield *num;
|
||||
*num += 1; //~ ERROR dangling pointer was dereferenced
|
||||
*num += 1; //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ fn main() {
|
|||
let base_addr = x as *mut _ as usize;
|
||||
let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 };
|
||||
let u16_ptr = base_addr_aligned as *mut u16;
|
||||
unsafe { *u16_ptr = 2; } //~ ERROR tried to access memory with alignment 1, but alignment 2 is required
|
||||
unsafe { *u16_ptr = 2; } //~ ERROR memory with alignment 1, but alignment 2 is required
|
||||
println!("{:?}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
|
||||
fn main() {
|
||||
let b = unsafe { std::mem::transmute::<u8, bool>(2) };
|
||||
let _x = b == true; //~ ERROR invalid boolean value read
|
||||
let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
fn main() {
|
||||
assert!(std::char::from_u32(-1_i32 as u32).is_none());
|
||||
let c = unsafe { std::mem::transmute::<i32, char>(-1) };
|
||||
let _x = c == 'x'; //~ ERROR tried to interpret an invalid 32-bit value as a char
|
||||
let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@
|
|||
fn main() {
|
||||
let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee
|
||||
let y = unsafe { &mut *(x as *const i32 as *mut i32) };
|
||||
*y = 42; //~ ERROR tried to modify constant memory
|
||||
*y = 42; //~ ERROR read-only
|
||||
assert_eq!(*x, 42);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern: must be in-bounds at offset 5, but is outside bounds of allocation
|
||||
// error-pattern: must be in-bounds at offset 5, but is outside bounds of alloc
|
||||
fn main() {
|
||||
let v = [0i8; 4];
|
||||
let x = &v as *const i8;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
let v: Vec<u8> = vec![1, 2];
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
let v: Vec<u8> = vec![1, 2];
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation
|
||||
let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use std::intrinsics::*;
|
||||
|
||||
//error-pattern: Overflowing shift by 64 in `unchecked_shr`
|
||||
//error-pattern: overflowing shift by 64 in `unchecked_shr`
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,6 @@ fn main() {
|
|||
// "attempted to interpret some raw bytes as a pointer address" instead of
|
||||
// "attempted to read undefined bytes"
|
||||
}
|
||||
let x = *p; //~ ERROR attempted to read undefined bytes
|
||||
let x = *p; //~ ERROR this operation requires initialized memory
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ fn main() {
|
|||
let y = &x;
|
||||
let z = &y as *const &i32 as *const u8;
|
||||
// the deref fails, because we are reading only a part of the pointer
|
||||
let _val = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes
|
||||
let _val = unsafe { *z }; //~ ERROR unable to turn pointer into raw bytes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern: dangling pointer was dereferenced
|
||||
// error-pattern: invalid use of 1 as a pointer
|
||||
|
||||
fn main() {
|
||||
// Can't offset an integer pointer by non-zero offset.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern: dangling pointer was dereferenced
|
||||
// error-pattern: invalid use of 1 as a pointer
|
||||
|
||||
fn main() {
|
||||
let ptr = Box::into_raw(Box::new(0u32));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern: outside bounds of allocation
|
||||
// error-pattern: outside bounds of alloc
|
||||
|
||||
fn main() {
|
||||
let x = Box::into_raw(Box::new(0u32));
|
||||
|
|
|
|||
|
|
@ -17,5 +17,5 @@ fn main() {
|
|||
drop(strong);
|
||||
// But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to
|
||||
// undefined behaviour.
|
||||
assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dangling pointer
|
||||
assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,6 @@ fn main() {
|
|||
// starts 1 byte to the right, so using it would actually be wrong!
|
||||
let d_alias = &mut w.data as *mut _ as *mut *const u8;
|
||||
unsafe {
|
||||
let _x = *d_alias; //~ ERROR tried to access part of a pointer value as raw bytes
|
||||
let _x = *d_alias; //~ ERROR unable to turn pointer into raw bytes
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
use alloc::alloc::Global;
|
||||
use std::alloc::{AllocRef, Layout};
|
||||
|
||||
// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1
|
||||
// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ fn main() {
|
|||
unsafe {
|
||||
let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0;
|
||||
Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap();
|
||||
let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced
|
||||
let _z = *(x.as_ptr() as *mut u8); //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
use alloc::alloc::Global;
|
||||
use std::alloc::{AllocRef, Layout};
|
||||
|
||||
// error-pattern: dangling pointer was dereferenced
|
||||
// error-pattern: dereferenced after this allocation got freed
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ fn main() {
|
|||
y: 99,
|
||||
};
|
||||
let p = unsafe { &foo.x };
|
||||
let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required
|
||||
let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Validation/SB changes why we fail
|
||||
// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows
|
||||
|
||||
// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind
|
||||
// error-pattern: deallocating `Stack` memory using `Machine(Rust)` deallocation operation
|
||||
|
||||
fn main() {
|
||||
let x = 42;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// error-pattern: dangling pointer was dereferenced
|
||||
// error-pattern: invalid use of 4 as a pointer
|
||||
use std::ptr::NonNull;
|
||||
|
||||
fn main() { unsafe {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ static X: usize = 5;
|
|||
#[allow(mutable_transmutes)]
|
||||
fn main() {
|
||||
unsafe {
|
||||
*std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR tried to modify constant memory
|
||||
*std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR read-only
|
||||
assert_eq!(X, 6);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ use std::mem::transmute;
|
|||
fn main() {
|
||||
unsafe {
|
||||
let s = "this is a test";
|
||||
transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR tried to modify constant memory
|
||||
transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR read-only
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,6 @@ use std::mem::transmute;
|
|||
fn main() {
|
||||
unsafe {
|
||||
let bs = b"this is a test";
|
||||
transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR tried to modify constant memory
|
||||
transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR read-only
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ fn fill(v: &mut i32) {
|
|||
}
|
||||
|
||||
fn evil() {
|
||||
unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced
|
||||
unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -18,5 +18,5 @@ fn main() {
|
|||
}
|
||||
let v = unsafe { *z.offset(first_undef) };
|
||||
if v == 0 {}
|
||||
//~^ ERROR attempted to read undefined bytes
|
||||
//~^ ERROR this operation requires initialized memory
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ fn main() {
|
|||
let bad = unsafe {
|
||||
std::mem::transmute::<&[u8], [u8; 8]>(&[1u8])
|
||||
};
|
||||
let _val = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes
|
||||
let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn pointer into raw bytes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,5 @@ fn main() {
|
|||
let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error.
|
||||
let x = &x[0] as *const _ as *const u32;
|
||||
// This must fail because alignment is violated: the allocation's base is not sufficiently aligned.
|
||||
let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required
|
||||
let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ fn main() {
|
|||
let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32;
|
||||
// This must fail because alignment is violated: the offset is not sufficiently aligned.
|
||||
// Also make the offset not a power of 2, that used to ICE.
|
||||
let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required
|
||||
let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,5 +7,5 @@ fn main() {
|
|||
// This must fail because alignment is violated. Test specifically for loading pointers,
|
||||
// which have special code in miri's memory.
|
||||
let _x = unsafe { *x };
|
||||
//~^ ERROR tried to access memory with alignment 2, but alignment
|
||||
//~^ ERROR memory with alignment 2, but alignment
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ fn main() {
|
|||
let x = x as *const _ as *const [u32; 0];
|
||||
// This must fail because alignment is violated. Test specifically for loading ZST.
|
||||
let _x = unsafe { *x };
|
||||
//~^ ERROR tried to access memory with alignment 2, but alignment 4 is required
|
||||
//~^ ERROR memory with alignment 2, but alignment 4 is required
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MAX overflow
|
||||
unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add`
|
||||
unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR overflow executing `unchecked_add`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MIN overflow
|
||||
unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add`
|
||||
unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR overflow executing `unchecked_add`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MIN/-1 cannot be represented
|
||||
unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR Overflow executing `unchecked_div`
|
||||
unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow executing `unchecked_div`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MAX overflow
|
||||
unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul`
|
||||
unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR overflow executing `unchecked_mul`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MIN overflow
|
||||
unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul`
|
||||
unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR overflow executing `unchecked_mul`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MIN overflow
|
||||
unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub`
|
||||
unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR overflow executing `unchecked_sub`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#![feature(core_intrinsics)]
|
||||
fn main() {
|
||||
// MAX overflow
|
||||
unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub`
|
||||
unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR overflow executing `unchecked_sub`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
fn main() {
|
||||
let v: Vec<u8> = Vec::with_capacity(10);
|
||||
let undef = unsafe { *v.get_unchecked(5) };
|
||||
let x = undef + 1; //~ ERROR attempted to read undefined bytes
|
||||
let x = undef + 1; //~ ERROR this operation requires initialized memory
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (not entirely in bounds)
|
||||
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR reference to unallocated address 16
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ use std::mem;
|
|||
fn main() {
|
||||
let val = 14;
|
||||
let ptr = (&val as *const i32).wrapping_offset(1);
|
||||
let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (not entirely in bounds)
|
||||
let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (going beyond the bounds of its allocation)
|
||||
}
|
||||
|
|
|
|||
10
tests/compile-fail/validity/dangling_ref3.rs
Normal file
10
tests/compile-fail/validity/dangling_ref3.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
use std::mem;
|
||||
|
||||
fn dangling() -> *const u8 {
|
||||
let x = 0u8;
|
||||
&x as *const _
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR dangling reference (use-after-free)
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
fn main() {
|
||||
let p = 44 as *const i32;
|
||||
let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced
|
||||
let x = unsafe { *p }; //~ ERROR invalid use of 44 as a pointer
|
||||
panic!("this should never print: {}", x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@ fn main() {
|
|||
let mut x_box = Box::new(1u8);
|
||||
let x = &mut *x_box as *mut _ as *mut [u8; 0];
|
||||
drop(x_box);
|
||||
unsafe { *x = zst_val; } //~ ERROR dangling pointer was dereferenced
|
||||
unsafe { *x = zst_val; } //~ ERROR dereferenced after this allocation got freed
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue