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:
bors 2020-03-19 07:42:53 +00:00
commit 0ff05c4cfe
77 changed files with 185 additions and 207 deletions

View file

@ -1 +1 @@
660326e9791d5caf3186b14521498c2584a494ab
57e1da59cd0761330b4ea8d47b16340a78eeafa9

View file

@ -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())
})?)
}

View file

@ -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))
}
}
})

View file

@ -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),
})
}
}

View file

@ -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(())
}
}

View file

@ -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)
}
}

View file

@ -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)? {

View file

@ -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" => {

View file

@ -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)
}
},
}

View file

@ -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> {}

View file

@ -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),
}
}

View file

@ -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");
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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()
}

View file

@ -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
}

View file

@ -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

View file

@ -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);
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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 {

View file

@ -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
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 {

View file

@ -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);
}

View file

@ -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
}

View file

@ -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.

View file

@ -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));

View file

@ -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));

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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;

View file

@ -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 {

View file

@ -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);
}
}

View file

@ -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
}
}

View file

@ -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
}
}

View file

@ -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() {

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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`
}

View file

@ -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);
}

View file

@ -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
}

View file

@ -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)
}

View 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)
}

View file

@ -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);
}

View file

@ -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
}