make eval_libc functions ICE on any problem
This commit is contained in:
parent
c905ef4a6b
commit
f0bb7c7264
13 changed files with 201 additions and 180 deletions
|
|
@ -138,55 +138,77 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
.unwrap_or_else(|| panic!("failed to find required Rust item: {path:?}"))
|
||||
}
|
||||
|
||||
/// Evaluates the scalar at the specified path. Returns Some(val)
|
||||
/// if the path could be resolved, and None otherwise
|
||||
fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
/// Evaluates the scalar at the specified path.
|
||||
fn eval_path_scalar(&self, path: &[&str]) -> Scalar<Provenance> {
|
||||
let this = self.eval_context_ref();
|
||||
let instance = this.resolve_path(path, Namespace::ValueNS);
|
||||
let cid = GlobalId { instance, promoted: None };
|
||||
// We don't give a span -- this isn't actually used directly by the program anyway.
|
||||
let const_val = this.eval_global(cid, None)?;
|
||||
let const_val = this
|
||||
.eval_global(cid, None)
|
||||
.unwrap_or_else(|err| panic!("failed to evaluate required Rust item: {path:?}\n{err}"));
|
||||
this.read_scalar(&const_val.into())
|
||||
.unwrap_or_else(|err| panic!("failed to read required Rust item: {path:?}\n{err}"))
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as a `Scalar`.
|
||||
fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
fn eval_libc(&self, name: &str) -> Scalar<Provenance> {
|
||||
self.eval_path_scalar(&["libc", name])
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as an `i32`.
|
||||
fn eval_libc_i32(&self, name: &str) -> InterpResult<'tcx, i32> {
|
||||
fn eval_libc_i32(&self, name: &str) -> i32 {
|
||||
// TODO: Cache the result.
|
||||
self.eval_libc(name)?.to_i32()
|
||||
self.eval_libc(name).to_i32().unwrap_or_else(|_err| {
|
||||
panic!("required libc item has unexpected type (not `i32`): {name}")
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper function to get a `libc` constant as an `u32`.
|
||||
fn eval_libc_u32(&self, name: &str) -> u32 {
|
||||
// TODO: Cache the result.
|
||||
self.eval_libc(name).to_u32().unwrap_or_else(|_err| {
|
||||
panic!("required libc item has unexpected type (not `u32`): {name}")
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper function to get a `windows` constant as a `Scalar`.
|
||||
fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar<Provenance>> {
|
||||
fn eval_windows(&self, module: &str, name: &str) -> Scalar<Provenance> {
|
||||
self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name])
|
||||
}
|
||||
|
||||
/// Helper function to get a `windows` constant as a `u64`.
|
||||
fn eval_windows_u64(&self, module: &str, name: &str) -> InterpResult<'tcx, u64> {
|
||||
/// Helper function to get a `windows` constant as a `u32`.
|
||||
fn eval_windows_u32(&self, module: &str, name: &str) -> u32 {
|
||||
// TODO: Cache the result.
|
||||
self.eval_windows(module, name)?.to_u64()
|
||||
self.eval_windows(module, name).to_u32().unwrap_or_else(|_err| {
|
||||
panic!("required Windows item has unexpected type (not `u32`): {module}::{name}")
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper function to get a `windows` constant as a `u64`.
|
||||
fn eval_windows_u64(&self, module: &str, name: &str) -> u64 {
|
||||
// TODO: Cache the result.
|
||||
self.eval_windows(module, name).to_u64().unwrap_or_else(|_err| {
|
||||
panic!("required Windows item has unexpected type (not `u64`): {module}::{name}")
|
||||
})
|
||||
}
|
||||
|
||||
/// Helper function to get the `TyAndLayout` of a `libc` type
|
||||
fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
fn libc_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this
|
||||
.resolve_path(&["libc", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty)
|
||||
this.layout_of(ty).unwrap()
|
||||
}
|
||||
|
||||
/// Helper function to get the `TyAndLayout` of a `windows` type
|
||||
fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> {
|
||||
fn windows_ty_layout(&self, name: &str) -> TyAndLayout<'tcx> {
|
||||
let this = self.eval_context_ref();
|
||||
let ty = this
|
||||
.resolve_path(&["std", "sys", "windows", "c", name], Namespace::TypeNS)
|
||||
.ty(*this.tcx, ty::ParamEnv::reveal_all());
|
||||
this.layout_of(ty)
|
||||
this.layout_of(ty).unwrap()
|
||||
}
|
||||
|
||||
/// Project to the given *named* field of the mplace (which must be a struct or union type).
|
||||
|
|
@ -609,14 +631,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if target.families.iter().any(|f| f == "unix") {
|
||||
for &(name, kind) in UNIX_IO_ERROR_TABLE {
|
||||
if err_kind == kind {
|
||||
return this.eval_libc(name);
|
||||
return Ok(this.eval_libc(name));
|
||||
}
|
||||
}
|
||||
throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind)
|
||||
} else if target.families.iter().any(|f| f == "windows") {
|
||||
// FIXME: we have to finish implementing the Windows equivalent of this.
|
||||
use std::io::ErrorKind::*;
|
||||
this.eval_windows(
|
||||
Ok(this.eval_windows(
|
||||
"c",
|
||||
match err_kind {
|
||||
NotFound => "ERROR_FILE_NOT_FOUND",
|
||||
|
|
@ -627,7 +649,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
err_kind
|
||||
),
|
||||
},
|
||||
)
|
||||
))
|
||||
} else {
|
||||
throw_unsup_format!(
|
||||
"converting io::Error into errnum is unsupported for OS {}",
|
||||
|
|
@ -647,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if target.families.iter().any(|f| f == "unix") {
|
||||
let errnum = errnum.to_i32()?;
|
||||
for &(name, kind) in UNIX_IO_ERROR_TABLE {
|
||||
if errnum == this.eval_libc_i32(name)? {
|
||||
if errnum == this.eval_libc_i32(name) {
|
||||
return Ok(Some(kind));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
))
|
||||
}
|
||||
None => {
|
||||
let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND")?;
|
||||
let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND");
|
||||
this.set_last_error(envvar_not_found)?;
|
||||
Scalar::from_u32(0) // return zero upon failure
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(0) // return zero on success
|
||||
} else {
|
||||
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
Ok(-1)
|
||||
}
|
||||
|
|
@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
|
||||
this.update_environ()?;
|
||||
}
|
||||
Ok(this.eval_windows("c", "TRUE")?)
|
||||
Ok(this.eval_windows("c", "TRUE"))
|
||||
} else {
|
||||
let value = this.read_os_str_from_wide_str(value_ptr)?;
|
||||
let var_ptr = alloc_env_var_as_wide_str(&name, &value, this)?;
|
||||
|
|
@ -282,7 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?;
|
||||
}
|
||||
this.update_environ()?;
|
||||
Ok(this.eval_windows("c", "TRUE")?)
|
||||
Ok(this.eval_windows("c", "TRUE"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(0)
|
||||
} else {
|
||||
// name argument is a null pointer, points to an empty string, or points to a string containing an '=' character.
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
Ok(-1)
|
||||
}
|
||||
|
|
@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if this.write_path_to_c_str(&cwd, buf, size)?.0 {
|
||||
return Ok(buf);
|
||||
}
|
||||
let erange = this.eval_libc("ERANGE")?;
|
||||
let erange = this.eval_libc("ERANGE");
|
||||
this.set_last_error(erange)?;
|
||||
}
|
||||
Err(e) => this.set_last_error_from_io_error(e.kind())?,
|
||||
|
|
@ -411,14 +411,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?;
|
||||
this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
|
||||
|
||||
return this.eval_windows("c", "FALSE");
|
||||
return Ok(this.eval_windows("c", "FALSE"));
|
||||
}
|
||||
|
||||
match env::set_current_dir(path) {
|
||||
Ok(()) => this.eval_windows("c", "TRUE"),
|
||||
Ok(()) => Ok(this.eval_windows("c", "TRUE")),
|
||||
Err(e) => {
|
||||
this.set_last_error_from_io_error(e.kind())?;
|
||||
this.eval_windows("c", "FALSE")
|
||||
Ok(this.eval_windows("c", "FALSE"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,26 +36,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Linux further distinguishes regular and "coarse" clocks, but the "coarse" version
|
||||
// is just specified to be "faster and less precise", so we implement both the same way.
|
||||
absolute_clocks = vec![
|
||||
this.eval_libc_i32("CLOCK_REALTIME")?,
|
||||
this.eval_libc_i32("CLOCK_REALTIME_COARSE")?,
|
||||
this.eval_libc_i32("CLOCK_REALTIME"),
|
||||
this.eval_libc_i32("CLOCK_REALTIME_COARSE"),
|
||||
];
|
||||
// The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are
|
||||
// never allowed to go backwards. We don't need to do any additonal monotonicity
|
||||
// enforcement because std::time::Instant already guarantees that it is monotonic.
|
||||
relative_clocks = vec![
|
||||
this.eval_libc_i32("CLOCK_MONOTONIC")?,
|
||||
this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?,
|
||||
this.eval_libc_i32("CLOCK_MONOTONIC"),
|
||||
this.eval_libc_i32("CLOCK_MONOTONIC_COARSE"),
|
||||
];
|
||||
}
|
||||
"macos" => {
|
||||
absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")?];
|
||||
relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")?];
|
||||
absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")];
|
||||
relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")];
|
||||
// Some clocks only seem to exist in the aarch64 version of the target.
|
||||
if this.tcx.sess.target.arch == "aarch64" {
|
||||
// `CLOCK_UPTIME_RAW` supposed to not increment while the system is asleep... but
|
||||
// that's not really something a program running inside Miri can tell, anyway.
|
||||
// We need to support it because std uses it.
|
||||
relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW")?);
|
||||
relative_clocks.push(this.eval_libc_i32("CLOCK_UPTIME_RAW"));
|
||||
}
|
||||
}
|
||||
target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
|
||||
|
|
@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.machine.clock.now().duration_since(this.machine.clock.anchor())
|
||||
} else {
|
||||
// Unsupported clock.
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
};
|
||||
|
|
@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Using tz is obsolete and should always be null
|
||||
let tz = this.read_pointer(tz_op)?;
|
||||
if !this.ptr_is_null(tz)? {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -118,9 +118,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.assert_target_os("windows", "GetSystemTimeAsFileTime");
|
||||
this.check_no_isolation("`GetSystemTimeAsFileTime`")?;
|
||||
|
||||
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?;
|
||||
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?;
|
||||
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?;
|
||||
let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC");
|
||||
let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC");
|
||||
let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH");
|
||||
let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC;
|
||||
let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC;
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let duration = match this.read_timespec(&this.deref_operand(req_op)?)? {
|
||||
Some(duration) => duration,
|
||||
None => {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,12 +303,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
return Ok(());
|
||||
}
|
||||
let thread_callback =
|
||||
this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?;
|
||||
this.eval_windows("thread_local_key", "p_thread_callback").to_pointer(this)?;
|
||||
let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?;
|
||||
|
||||
// FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits
|
||||
// but std treats both the same.
|
||||
let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?;
|
||||
let reason = this.eval_windows("c", "DLL_THREAD_DETACH");
|
||||
|
||||
// The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`.
|
||||
// FIXME: `h` should be a handle to the current module and what `pv` should be is unknown
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Align must be power of 2, and also at least ptr-sized (POSIX rules).
|
||||
// But failure to adhere to this is not UB, it's an error condition.
|
||||
if !align.is_power_of_two() || align < this.pointer_size().bytes() {
|
||||
let einval = this.eval_libc_i32("EINVAL")?;
|
||||
let einval = this.eval_libc_i32("EINVAL");
|
||||
this.write_int(einval, dest)?;
|
||||
} else {
|
||||
if size == 0 {
|
||||
|
|
@ -243,7 +243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
];
|
||||
let mut result = None;
|
||||
for &(sysconf_name, value) in sysconfs {
|
||||
let sysconf_name = this.eval_libc_i32(sysconf_name)?;
|
||||
let sysconf_name = this.eval_libc_i32(sysconf_name);
|
||||
if sysconf_name == name {
|
||||
result = Some(value(this));
|
||||
break;
|
||||
|
|
@ -480,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
None => format!("<unknown errnum in strerror_r: {errnum}>"),
|
||||
};
|
||||
let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?;
|
||||
let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? };
|
||||
let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE") };
|
||||
this.write_int(ret, dest)?;
|
||||
}
|
||||
"getpid" => {
|
||||
|
|
@ -495,7 +495,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if this.frame_in_std() => {
|
||||
let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let guard_size = this.deref_operand(guard_size)?;
|
||||
let guard_size_layout = this.libc_ty_layout("size_t")?;
|
||||
let guard_size_layout = this.libc_ty_layout("size_t");
|
||||
this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size.into())?;
|
||||
|
||||
// Return success (`0`).
|
||||
|
|
@ -589,7 +589,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.write_null(dest)?;
|
||||
} else {
|
||||
this.write_null(&result.into())?;
|
||||
this.write_scalar(this.eval_libc("ERANGE")?, dest)?;
|
||||
this.write_scalar(this.eval_libc("ERANGE"), dest)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
|
|||
/// types (like `read`, that returns an `i64`).
|
||||
fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
|
||||
let this = self.eval_context_mut();
|
||||
let ebadf = this.eval_libc("EBADF")?;
|
||||
let ebadf = this.eval_libc("EBADF");
|
||||
this.set_last_error(ebadf)?;
|
||||
Ok((-1).into())
|
||||
}
|
||||
|
|
@ -395,11 +395,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
|
|||
match file_type {
|
||||
Ok(file_type) => {
|
||||
if file_type.is_dir() {
|
||||
Ok(this.eval_libc("DT_DIR")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_DIR").to_u8()?.into())
|
||||
} else if file_type.is_file() {
|
||||
Ok(this.eval_libc("DT_REG")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_REG").to_u8()?.into())
|
||||
} else if file_type.is_symlink() {
|
||||
Ok(this.eval_libc("DT_LNK")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_LNK").to_u8()?.into())
|
||||
} else {
|
||||
// Certain file types are only supported when the host is a Unix system.
|
||||
// (i.e. devices and sockets) If it is, check those cases, if not, fall back to
|
||||
|
|
@ -409,19 +409,19 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx
|
|||
{
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
if file_type.is_block_device() {
|
||||
Ok(this.eval_libc("DT_BLK")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_BLK").to_u8()?.into())
|
||||
} else if file_type.is_char_device() {
|
||||
Ok(this.eval_libc("DT_CHR")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_CHR").to_u8()?.into())
|
||||
} else if file_type.is_fifo() {
|
||||
Ok(this.eval_libc("DT_FIFO")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_FIFO").to_u8()?.into())
|
||||
} else if file_type.is_socket() {
|
||||
Ok(this.eval_libc("DT_SOCK")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_SOCK").to_u8()?.into())
|
||||
} else {
|
||||
Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
|
||||
}
|
||||
}
|
||||
#[cfg(not(unix))]
|
||||
Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into())
|
||||
Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
|
||||
}
|
||||
}
|
||||
Err(e) =>
|
||||
|
|
@ -532,9 +532,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let mut options = OpenOptions::new();
|
||||
|
||||
let o_rdonly = this.eval_libc_i32("O_RDONLY")?;
|
||||
let o_wronly = this.eval_libc_i32("O_WRONLY")?;
|
||||
let o_rdwr = this.eval_libc_i32("O_RDWR")?;
|
||||
let o_rdonly = this.eval_libc_i32("O_RDONLY");
|
||||
let o_wronly = this.eval_libc_i32("O_WRONLY");
|
||||
let o_rdwr = this.eval_libc_i32("O_RDWR");
|
||||
// The first two bits of the flag correspond to the access mode in linux, macOS and
|
||||
// windows. We need to check that in fact the access mode flags for the current target
|
||||
// only use these two bits, otherwise we are in an unsupported target and should error.
|
||||
|
|
@ -561,17 +561,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// options.
|
||||
let mut mirror = access_mode;
|
||||
|
||||
let o_append = this.eval_libc_i32("O_APPEND")?;
|
||||
let o_append = this.eval_libc_i32("O_APPEND");
|
||||
if flag & o_append == o_append {
|
||||
options.append(true);
|
||||
mirror |= o_append;
|
||||
}
|
||||
let o_trunc = this.eval_libc_i32("O_TRUNC")?;
|
||||
let o_trunc = this.eval_libc_i32("O_TRUNC");
|
||||
if flag & o_trunc == o_trunc {
|
||||
options.truncate(true);
|
||||
mirror |= o_trunc;
|
||||
}
|
||||
let o_creat = this.eval_libc_i32("O_CREAT")?;
|
||||
let o_creat = this.eval_libc_i32("O_CREAT");
|
||||
if flag & o_creat == o_creat {
|
||||
// Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but
|
||||
// C integer promotion rules mean that on the ABI level, it gets passed as `u32`
|
||||
|
|
@ -591,7 +591,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
mirror |= o_creat;
|
||||
|
||||
let o_excl = this.eval_libc_i32("O_EXCL")?;
|
||||
let o_excl = this.eval_libc_i32("O_EXCL");
|
||||
if flag & o_excl == o_excl {
|
||||
mirror |= o_excl;
|
||||
options.create_new(true);
|
||||
|
|
@ -599,17 +599,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
options.create(true);
|
||||
}
|
||||
}
|
||||
let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?;
|
||||
let o_cloexec = this.eval_libc_i32("O_CLOEXEC");
|
||||
if flag & o_cloexec == o_cloexec {
|
||||
// We do not need to do anything for this flag because `std` already sets it.
|
||||
// (Technically we do not support *not* setting this flag, but we ignore that.)
|
||||
mirror |= o_cloexec;
|
||||
}
|
||||
if this.tcx.sess.target.os == "linux" {
|
||||
let o_tmpfile = this.eval_libc_i32("O_TMPFILE")?;
|
||||
let o_tmpfile = this.eval_libc_i32("O_TMPFILE");
|
||||
if flag & o_tmpfile == o_tmpfile {
|
||||
// if the flag contains `O_TMPFILE` then we return a graceful error
|
||||
let eopnotsupp = this.eval_libc("EOPNOTSUPP")?;
|
||||
let eopnotsupp = this.eval_libc("EOPNOTSUPP");
|
||||
this.set_last_error(eopnotsupp)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -657,18 +657,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
// We only support getting the flags for a descriptor.
|
||||
if cmd == this.eval_libc_i32("F_GETFD")? {
|
||||
if cmd == this.eval_libc_i32("F_GETFD") {
|
||||
// Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
|
||||
// `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
|
||||
// always sets this flag when opening a file. However we still need to check that the
|
||||
// file itself is open.
|
||||
if this.machine.file_handler.handles.contains_key(&fd) {
|
||||
Ok(this.eval_libc_i32("FD_CLOEXEC")?)
|
||||
Ok(this.eval_libc_i32("FD_CLOEXEC"))
|
||||
} else {
|
||||
this.handle_not_found()
|
||||
}
|
||||
} else if cmd == this.eval_libc_i32("F_DUPFD")?
|
||||
|| cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")?
|
||||
} else if cmd == this.eval_libc_i32("F_DUPFD")
|
||||
|| cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")
|
||||
{
|
||||
// Note that we always assume the FD_CLOEXEC flag is set for every open file, in part
|
||||
// because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only
|
||||
|
|
@ -697,7 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
None => this.handle_not_found(),
|
||||
}
|
||||
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? {
|
||||
} else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") {
|
||||
if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) {
|
||||
// FIXME: Support fullfsync for all FDs
|
||||
let FileHandle { file, writable } = file_descriptor.as_file_handle()?;
|
||||
|
|
@ -830,14 +830,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let offset = this.read_scalar(offset_op)?.to_i64()?;
|
||||
let whence = this.read_scalar(whence_op)?.to_i32()?;
|
||||
|
||||
let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? {
|
||||
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
|
||||
SeekFrom::Start(u64::try_from(offset).unwrap())
|
||||
} else if whence == this.eval_libc_i32("SEEK_CUR")? {
|
||||
} else if whence == this.eval_libc_i32("SEEK_CUR") {
|
||||
SeekFrom::Current(offset)
|
||||
} else if whence == this.eval_libc_i32("SEEK_END")? {
|
||||
} else if whence == this.eval_libc_i32("SEEK_END") {
|
||||
SeekFrom::End(offset)
|
||||
} else {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(Scalar::from_i64(-1));
|
||||
};
|
||||
|
|
@ -916,7 +916,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`stat`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
}
|
||||
|
|
@ -945,7 +945,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`lstat`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
}
|
||||
|
|
@ -1003,7 +1003,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
// If the statxbuf or pathname pointers are null, the function fails with `EFAULT`.
|
||||
if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? {
|
||||
let efault = this.eval_libc("EFAULT")?;
|
||||
let efault = this.eval_libc("EFAULT");
|
||||
this.set_last_error(efault)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -1014,13 +1014,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// as `isize`s instead of having the proper types. Thus, we have to recover the layout of
|
||||
// `statxbuf_op` by using the `libc::statx` struct type.
|
||||
let statxbuf = {
|
||||
let statx_layout = this.libc_ty_layout("statx")?;
|
||||
let statx_layout = this.libc_ty_layout("statx");
|
||||
MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout)
|
||||
};
|
||||
|
||||
let path = this.read_path_from_c_str(pathname_ptr)?.into_owned();
|
||||
// See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
|
||||
let at_ampty_path = this.eval_libc_i32("AT_EMPTY_PATH")?;
|
||||
let at_ampty_path = this.eval_libc_i32("AT_EMPTY_PATH");
|
||||
let empty_path_flag = flags & at_ampty_path == at_ampty_path;
|
||||
// We only support:
|
||||
// * interpreting `path` as an absolute directory,
|
||||
|
|
@ -1030,7 +1030,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Other behaviors cannot be tested from `libstd` and thus are not implemented. If you
|
||||
// found this error, please open an issue reporting it.
|
||||
if !(path.is_absolute()
|
||||
|| dirfd == this.eval_libc_i32("AT_FDCWD")?
|
||||
|| dirfd == this.eval_libc_i32("AT_FDCWD")
|
||||
|| (path.as_os_str().is_empty() && empty_path_flag))
|
||||
{
|
||||
throw_unsup_format!(
|
||||
|
|
@ -1043,16 +1043,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`statx`", reject_with)?;
|
||||
let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? {
|
||||
let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD") {
|
||||
// since `path` is provided, either absolute or
|
||||
// relative to CWD, `EACCES` is the most relevant.
|
||||
this.eval_libc("EACCES")?
|
||||
this.eval_libc("EACCES")
|
||||
} else {
|
||||
// `dirfd` is set to target file, and `path` is empty
|
||||
// (or we would have hit the `throw_unsup_format`
|
||||
// above). `EACCES` would violate the spec.
|
||||
assert!(empty_path_flag);
|
||||
this.eval_libc("EBADF")?
|
||||
this.eval_libc("EBADF")
|
||||
};
|
||||
this.set_last_error(ecode)?;
|
||||
return Ok(-1);
|
||||
|
|
@ -1062,12 +1062,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// However `statx` is allowed to return information that was not requested or to not
|
||||
// return information that was requested. This `mask` represents the information we can
|
||||
// actually provide for any target.
|
||||
let mut mask =
|
||||
this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?;
|
||||
let mut mask = this.eval_libc_u32("STATX_TYPE") | this.eval_libc_u32("STATX_SIZE");
|
||||
|
||||
// If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following
|
||||
// symbolic links.
|
||||
let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0;
|
||||
let follow_symlink = flags & this.eval_libc_i32("AT_SYMLINK_NOFOLLOW") == 0;
|
||||
|
||||
// If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file
|
||||
// represented by dirfd, whether it's a directory or otherwise.
|
||||
|
|
@ -1096,7 +1095,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let (access_sec, access_nsec) = metadata
|
||||
.accessed
|
||||
.map(|tup| {
|
||||
mask |= this.eval_libc("STATX_ATIME")?.to_u32()?;
|
||||
mask |= this.eval_libc_u32("STATX_ATIME");
|
||||
InterpResult::Ok(tup)
|
||||
})
|
||||
.unwrap_or_else(|| Ok((0, 0)))?;
|
||||
|
|
@ -1104,7 +1103,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let (created_sec, created_nsec) = metadata
|
||||
.created
|
||||
.map(|tup| {
|
||||
mask |= this.eval_libc("STATX_BTIME")?.to_u32()?;
|
||||
mask |= this.eval_libc_u32("STATX_BTIME");
|
||||
InterpResult::Ok(tup)
|
||||
})
|
||||
.unwrap_or_else(|| Ok((0, 0)))?;
|
||||
|
|
@ -1112,7 +1111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let (modified_sec, modified_nsec) = metadata
|
||||
.modified
|
||||
.map(|tup| {
|
||||
mask |= this.eval_libc("STATX_MTIME")?.to_u32()?;
|
||||
mask |= this.eval_libc_u32("STATX_MTIME");
|
||||
InterpResult::Ok(tup)
|
||||
})
|
||||
.unwrap_or_else(|| Ok((0, 0)))?;
|
||||
|
|
@ -1185,7 +1184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let newpath_ptr = this.read_pointer(newpath_op)?;
|
||||
|
||||
if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? {
|
||||
let efault = this.eval_libc("EFAULT")?;
|
||||
let efault = this.eval_libc("EFAULT");
|
||||
this.set_last_error(efault)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -1272,7 +1271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`opendir`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::null_ptr(this));
|
||||
}
|
||||
|
|
@ -1308,7 +1307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`readdir`", reject_with)?;
|
||||
let eacc = this.eval_libc("EBADF")?;
|
||||
let eacc = this.eval_libc("EBADF");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::null_ptr(this));
|
||||
}
|
||||
|
|
@ -1337,7 +1336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let name_bytes = os_str_to_bytes(&name)?;
|
||||
let name_len = u64::try_from(name_bytes.len()).unwrap();
|
||||
|
||||
let dirent64_layout = this.libc_ty_layout("dirent64")?;
|
||||
let dirent64_layout = this.libc_ty_layout("dirent64");
|
||||
let d_name_offset = dirent64_layout.fields.offset(4 /* d_name */).bytes();
|
||||
let size = d_name_offset.checked_add(name_len).unwrap();
|
||||
|
||||
|
|
@ -1532,13 +1531,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let result = file.set_len(length);
|
||||
this.try_unwrap_io_result(result.map(|_| 0i32))?
|
||||
} else {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
-1
|
||||
}
|
||||
} else {
|
||||
// The file is not writable
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
-1
|
||||
}
|
||||
|
|
@ -1612,15 +1611,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let flags = this.read_scalar(flags_op)?.to_i32()?;
|
||||
|
||||
if offset < 0 || nbytes < 0 {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
}
|
||||
let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")?
|
||||
| this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")?
|
||||
| this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER")?;
|
||||
let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")
|
||||
| this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")
|
||||
| this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER");
|
||||
if flags & allowed_flags != flags {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(Scalar::from_i32(-1));
|
||||
}
|
||||
|
|
@ -1657,7 +1656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`readlink`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -1702,7 +1701,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
// Fallback when the FD was not found or isolation is enabled.
|
||||
let enotty = this.eval_libc("ENOTTY")?;
|
||||
let enotty = this.eval_libc("ENOTTY");
|
||||
this.set_last_error(enotty)?;
|
||||
Ok(Scalar::from_i32(0))
|
||||
}
|
||||
|
|
@ -1721,7 +1720,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`realpath`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(Scalar::from_machine_usize(0, this));
|
||||
}
|
||||
|
|
@ -1730,7 +1729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
match result {
|
||||
Ok(resolved) => {
|
||||
let path_max = this
|
||||
.eval_libc_i32("PATH_MAX")?
|
||||
.eval_libc_i32("PATH_MAX")
|
||||
.try_into()
|
||||
.expect("PATH_MAX does not fit in u64");
|
||||
let dest = if this.ptr_is_null(processed_ptr)? {
|
||||
|
|
@ -1752,7 +1751,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Note that we do not explicitly handle `FILENAME_MAX`
|
||||
// (different from `PATH_MAX` above) as it is Linux-specific and
|
||||
// seems like a bit of a mess anyway: <https://eklitzke.org/path-max-is-tricky>.
|
||||
let enametoolong = this.eval_libc("ENAMETOOLONG")?;
|
||||
let enametoolong = this.eval_libc("ENAMETOOLONG");
|
||||
this.set_last_error(enametoolong)?;
|
||||
return Ok(Scalar::from_machine_usize(0, this));
|
||||
}
|
||||
|
|
@ -1785,7 +1784,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// * The value of `TMP_MAX` is at least 25.
|
||||
// * On XSI-conformant systems, the value of `TMP_MAX` is at least 10000.
|
||||
// See <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/stdio.h.html>.
|
||||
let max_attempts = this.eval_libc("TMP_MAX")?.to_u32()?;
|
||||
let max_attempts = this.eval_libc_u32("TMP_MAX");
|
||||
|
||||
// Get the raw bytes from the template -- as a byte slice, this is a string in the target
|
||||
// (and the target is unix, so a byte slice is the right representation).
|
||||
|
|
@ -1796,7 +1795,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// Reject if isolation is enabled.
|
||||
if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
|
||||
this.reject_in_isolation("`mkstemp`", reject_with)?;
|
||||
let eacc = this.eval_libc("EACCES")?;
|
||||
let eacc = this.eval_libc("EACCES");
|
||||
this.set_last_error(eacc)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -1814,7 +1813,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
// If we don't find the suffix, it is an error.
|
||||
if last_six_char_bytes != suffix_bytes {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
return Ok(-1);
|
||||
}
|
||||
|
|
@ -1890,7 +1889,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
// We ran out of attempts to create the file, return an error.
|
||||
let eexist = this.eval_libc("EEXIST")?;
|
||||
let eexist = this.eval_libc("EEXIST");
|
||||
this.set_last_error(eexist)?;
|
||||
Ok(-1)
|
||||
}
|
||||
|
|
@ -1968,7 +1967,7 @@ impl FileMetadata {
|
|||
"S_IFLNK"
|
||||
};
|
||||
|
||||
let mode = ecx.eval_libc(mode_name)?;
|
||||
let mode = ecx.eval_libc(mode_name);
|
||||
|
||||
let size = metadata.len();
|
||||
|
||||
|
|
|
|||
|
|
@ -88,11 +88,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// argument, we have to also check all arguments *before* it to ensure that they
|
||||
// have the right type.
|
||||
|
||||
let sys_getrandom = this.eval_libc("SYS_getrandom")?.to_machine_usize(this)?;
|
||||
let sys_getrandom = this.eval_libc("SYS_getrandom").to_machine_usize(this)?;
|
||||
|
||||
let sys_statx = this.eval_libc("SYS_statx")?.to_machine_usize(this)?;
|
||||
let sys_statx = this.eval_libc("SYS_statx").to_machine_usize(this)?;
|
||||
|
||||
let sys_futex = this.eval_libc("SYS_futex")?.to_machine_usize(this)?;
|
||||
let sys_futex = this.eval_libc("SYS_futex").to_machine_usize(this)?;
|
||||
|
||||
if args.is_empty() {
|
||||
throw_ub_format!(
|
||||
|
|
@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.read_scalar(cpusetsize)?.to_machine_usize(this)?;
|
||||
this.deref_operand(mask)?;
|
||||
// FIXME: we just return an error; `num_cpus` then falls back to `sysconf`.
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
this.write_scalar(Scalar::from_i32(-1), dest)?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ pub fn futex<'tcx>(
|
|||
let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32);
|
||||
let addr_usize = addr.ptr.addr().bytes();
|
||||
|
||||
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
|
||||
let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
|
||||
let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?;
|
||||
let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?;
|
||||
let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET")?;
|
||||
let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?;
|
||||
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG");
|
||||
let futex_wait = this.eval_libc_i32("FUTEX_WAIT");
|
||||
let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET");
|
||||
let futex_wake = this.eval_libc_i32("FUTEX_WAKE");
|
||||
let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET");
|
||||
let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME");
|
||||
|
||||
// FUTEX_PRIVATE enables an optimization that stops it from working across processes.
|
||||
// Miri doesn't support that anyway, so we ignore that flag.
|
||||
|
|
@ -79,7 +79,7 @@ pub fn futex<'tcx>(
|
|||
};
|
||||
|
||||
if bitset == 0 {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
|
||||
return Ok(());
|
||||
|
|
@ -99,7 +99,7 @@ pub fn futex<'tcx>(
|
|||
let duration = match this.read_timespec(&timeout)? {
|
||||
Some(duration) => duration,
|
||||
None => {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
|
||||
return Ok(());
|
||||
|
|
@ -194,7 +194,7 @@ pub fn futex<'tcx>(
|
|||
fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
this.unblock_thread(self.thread);
|
||||
this.futex_remove_waiter(self.addr_usize, self.thread);
|
||||
let etimedout = this.eval_libc("ETIMEDOUT")?;
|
||||
let etimedout = this.eval_libc("ETIMEDOUT");
|
||||
this.set_last_error(etimedout)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), &self.dest)?;
|
||||
|
||||
|
|
@ -211,7 +211,7 @@ pub fn futex<'tcx>(
|
|||
} else {
|
||||
// The futex value doesn't match the expected value, so we return failure
|
||||
// right away without sleeping: -1 and errno set to EAGAIN.
|
||||
let eagain = this.eval_libc("EAGAIN")?;
|
||||
let eagain = this.eval_libc("EAGAIN");
|
||||
this.set_last_error(eagain)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
|
||||
}
|
||||
|
|
@ -237,7 +237,7 @@ pub fn futex<'tcx>(
|
|||
u32::MAX
|
||||
};
|
||||
if bitset == 0 {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.set_last_error(einval)?;
|
||||
this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?;
|
||||
return Ok(());
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
"pthread_setname_np" => {
|
||||
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
let thread = this.pthread_self()?;
|
||||
let max_len = this.eval_libc("MAXTHREADNAMESIZE")?.to_machine_usize(this)?;
|
||||
let max_len = this.eval_libc("MAXTHREADNAMESIZE").to_machine_usize(this)?;
|
||||
let res = this.pthread_setname_np(
|
||||
thread,
|
||||
this.read_scalar(name)?,
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ fn is_mutex_kind_default<'mir, 'tcx: 'mir>(
|
|||
ecx: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
kind: i32,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?)
|
||||
Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"))
|
||||
}
|
||||
|
||||
fn is_mutex_kind_normal<'mir, 'tcx: 'mir>(
|
||||
ecx: &mut MiriInterpCx<'mir, 'tcx>,
|
||||
kind: i32,
|
||||
) -> InterpResult<'tcx, bool> {
|
||||
let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL")?;
|
||||
let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL");
|
||||
Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG))
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> InterpResult<'tcx, i32> {
|
||||
let this = self.eval_context_mut();
|
||||
|
||||
let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?;
|
||||
let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT");
|
||||
mutexattr_set_kind(this, attr_op, default_kind)?;
|
||||
|
||||
Ok(0)
|
||||
|
|
@ -231,7 +231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let this = self.eval_context_mut();
|
||||
|
||||
let kind = this.read_scalar(kind_op)?.to_i32()?;
|
||||
if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL")? {
|
||||
if kind == this.eval_libc_i32("PTHREAD_MUTEX_NORMAL") {
|
||||
// In `glibc` implementation, the numeric values of
|
||||
// `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal.
|
||||
// However, a mutex created by explicitly passing
|
||||
|
|
@ -247,17 +247,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let normal_kind = kind | PTHREAD_MUTEX_NORMAL_FLAG;
|
||||
// Check that after setting the flag, the kind is distinguishable
|
||||
// from all other kinds.
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?);
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")?);
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")?);
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"));
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK"));
|
||||
assert_ne!(normal_kind, this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE"));
|
||||
mutexattr_set_kind(this, attr_op, normal_kind)?;
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")?
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")?
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
|
||||
{
|
||||
mutexattr_set_kind(this, attr_op, kind)?;
|
||||
} else {
|
||||
let einval = this.eval_libc_i32("EINVAL")?;
|
||||
let einval = this.eval_libc_i32("EINVAL");
|
||||
return Ok(einval);
|
||||
}
|
||||
|
||||
|
|
@ -299,7 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let attr = this.read_pointer(attr_op)?;
|
||||
let kind = if this.ptr_is_null(attr)? {
|
||||
this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")?
|
||||
this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")
|
||||
} else {
|
||||
mutexattr_get_kind(this, attr_op)?
|
||||
};
|
||||
|
|
@ -331,9 +331,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
throw_ub_format!("trying to acquire already locked default mutex");
|
||||
} else if is_mutex_kind_normal(this, kind)? {
|
||||
throw_machine_stop!(TerminationInfo::Deadlock);
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")? {
|
||||
this.eval_libc_i32("EDEADLK")
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? {
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK") {
|
||||
Ok(this.eval_libc_i32("EDEADLK"))
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
||||
this.mutex_lock(id, active_thread);
|
||||
Ok(0)
|
||||
} else {
|
||||
|
|
@ -362,14 +362,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if this.mutex_is_locked(id) {
|
||||
let owner_thread = this.mutex_get_owner(id);
|
||||
if owner_thread != active_thread {
|
||||
this.eval_libc_i32("EBUSY")
|
||||
Ok(this.eval_libc_i32("EBUSY"))
|
||||
} else {
|
||||
if is_mutex_kind_default(this, kind)?
|
||||
|| is_mutex_kind_normal(this, kind)?
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")?
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
||||
{
|
||||
this.eval_libc_i32("EBUSY")
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")? {
|
||||
Ok(this.eval_libc_i32("EBUSY"))
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE") {
|
||||
this.mutex_lock(id, active_thread);
|
||||
Ok(0)
|
||||
} else {
|
||||
|
|
@ -410,10 +410,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
throw_ub_format!(
|
||||
"unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread"
|
||||
);
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")?
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")?
|
||||
} else if kind == this.eval_libc_i32("PTHREAD_MUTEX_ERRORCHECK")
|
||||
|| kind == this.eval_libc_i32("PTHREAD_MUTEX_RECURSIVE")
|
||||
{
|
||||
this.eval_libc_i32("EPERM")
|
||||
Ok(this.eval_libc_i32("EPERM"))
|
||||
} else {
|
||||
throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex");
|
||||
}
|
||||
|
|
@ -471,7 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let active_thread = this.get_active_thread();
|
||||
|
||||
if this.rwlock_is_write_locked(id) {
|
||||
this.eval_libc_i32("EBUSY")
|
||||
Ok(this.eval_libc_i32("EBUSY"))
|
||||
} else {
|
||||
this.rwlock_reader_lock(id, active_thread);
|
||||
Ok(0)
|
||||
|
|
@ -518,7 +518,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let active_thread = this.get_active_thread();
|
||||
|
||||
if this.rwlock_is_locked(id) {
|
||||
this.eval_libc_i32("EBUSY")
|
||||
Ok(this.eval_libc_i32("EBUSY"))
|
||||
} else {
|
||||
this.rwlock_writer_lock(id, active_thread);
|
||||
Ok(0)
|
||||
|
|
@ -575,7 +575,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// The default value of the clock attribute shall refer to the system
|
||||
// clock.
|
||||
// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setclock.html
|
||||
let default_clock_id = this.eval_libc_i32("CLOCK_REALTIME")?;
|
||||
let default_clock_id = this.eval_libc_i32("CLOCK_REALTIME");
|
||||
condattr_set_clock_id(this, attr_op, default_clock_id)?;
|
||||
|
||||
Ok(0)
|
||||
|
|
@ -589,12 +589,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let this = self.eval_context_mut();
|
||||
|
||||
let clock_id = this.read_scalar(clock_id_op)?.to_i32()?;
|
||||
if clock_id == this.eval_libc_i32("CLOCK_REALTIME")?
|
||||
|| clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")?
|
||||
if clock_id == this.eval_libc_i32("CLOCK_REALTIME")
|
||||
|| clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")
|
||||
{
|
||||
condattr_set_clock_id(this, attr_op, clock_id)?;
|
||||
} else {
|
||||
let einval = this.eval_libc_i32("EINVAL")?;
|
||||
let einval = this.eval_libc_i32("EINVAL");
|
||||
return Ok(Scalar::from_i32(einval));
|
||||
}
|
||||
|
||||
|
|
@ -638,7 +638,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let attr = this.read_pointer(attr_op)?;
|
||||
let clock_id = if this.ptr_is_null(attr)? {
|
||||
this.eval_libc_i32("CLOCK_REALTIME")?
|
||||
this.eval_libc_i32("CLOCK_REALTIME")
|
||||
} else {
|
||||
condattr_get_clock_id(this, attr_op)?
|
||||
};
|
||||
|
|
@ -718,16 +718,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let duration = match this.read_timespec(&this.deref_operand(abstime_op)?)? {
|
||||
Some(duration) => duration,
|
||||
None => {
|
||||
let einval = this.eval_libc("EINVAL")?;
|
||||
let einval = this.eval_libc("EINVAL");
|
||||
this.write_scalar(einval, dest)?;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? {
|
||||
let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME") {
|
||||
this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
|
||||
Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
|
||||
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
|
||||
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") {
|
||||
Time::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap())
|
||||
} else {
|
||||
throw_unsup_format!("unsupported clock id: {}", clock_id);
|
||||
|
|
@ -763,7 +763,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
ecx.condvar_remove_waiter(self.id, self.active_thread);
|
||||
|
||||
// Set the return value: we timed out.
|
||||
let etimedout = ecx.eval_libc("ETIMEDOUT")?;
|
||||
let etimedout = ecx.eval_libc("ETIMEDOUT");
|
||||
ecx.write_scalar(etimedout, &self.dest)?;
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
// Comparing with `>=` to account for null terminator.
|
||||
if name.len() >= max_name_len {
|
||||
return this.eval_libc("ERANGE");
|
||||
return Ok(this.eval_libc("ERANGE"));
|
||||
}
|
||||
|
||||
this.set_thread_name(thread, name);
|
||||
|
|
@ -107,7 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let name = this.get_thread_name(thread).to_owned();
|
||||
let (success, _written) = this.write_c_str(&name, name_out, len)?;
|
||||
|
||||
if success { Ok(Scalar::from_u32(0)) } else { this.eval_libc("ERANGE") }
|
||||
Ok(if success { Scalar::from_u32(0) } else { this.eval_libc("ERANGE") })
|
||||
}
|
||||
|
||||
fn sched_yield(&mut self) -> InterpResult<'tcx, i32> {
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
match this.init_once_status(id) {
|
||||
InitOnceStatus::Uninitialized => {
|
||||
this.init_once_begin(id);
|
||||
this.write_scalar(this.eval_windows("c", "TRUE")?, &pending_place)?;
|
||||
this.write_scalar(this.eval_windows("c", "TRUE"), &pending_place)?;
|
||||
}
|
||||
InitOnceStatus::Begun => {
|
||||
// Someone else is already on it.
|
||||
|
|
@ -195,8 +195,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
unreachable!(
|
||||
"status should have either been set to begun or complete"
|
||||
),
|
||||
InitOnceStatus::Begun => this.eval_windows("c", "TRUE")?,
|
||||
InitOnceStatus::Complete => this.eval_windows("c", "FALSE")?,
|
||||
InitOnceStatus::Begun => this.eval_windows("c", "TRUE"),
|
||||
InitOnceStatus::Complete => this.eval_windows("c", "FALSE"),
|
||||
};
|
||||
|
||||
this.write_scalar(pending, &self.pending_place)?;
|
||||
|
|
@ -213,12 +213,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
InitOnceStatus::Complete => {
|
||||
this.init_once_observe_completed(id);
|
||||
this.write_scalar(this.eval_windows("c", "FALSE")?, &pending_place)?;
|
||||
this.write_scalar(this.eval_windows("c", "FALSE"), &pending_place)?;
|
||||
}
|
||||
}
|
||||
|
||||
// This always succeeds (even if the thread is blocked, we will succeed if we ever unblock).
|
||||
this.eval_windows("c", "TRUE")
|
||||
Ok(this.eval_windows("c", "TRUE"))
|
||||
}
|
||||
|
||||
fn InitOnceComplete(
|
||||
|
|
@ -235,7 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let success = if flags == 0 {
|
||||
true
|
||||
} else if flags == this.eval_windows("c", "INIT_ONCE_INIT_FAILED")?.to_u32()? {
|
||||
} else if flags == this.eval_windows_u32("c", "INIT_ONCE_INIT_FAILED") {
|
||||
false
|
||||
} else {
|
||||
throw_unsup_format!("unsupported `dwFlags` {flags} in `InitOnceBeginInitialize`");
|
||||
|
|
@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.init_once_fail(id)?;
|
||||
}
|
||||
|
||||
this.eval_windows("c", "TRUE")
|
||||
Ok(this.eval_windows("c", "TRUE"))
|
||||
}
|
||||
|
||||
fn WaitOnAddress(
|
||||
|
|
@ -280,14 +280,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let addr = ptr.addr().bytes();
|
||||
|
||||
if size > 8 || !size.is_power_of_two() {
|
||||
let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER")?;
|
||||
let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER");
|
||||
this.set_last_error(invalid_param)?;
|
||||
this.write_scalar(Scalar::from_i32(0), dest)?;
|
||||
return Ok(());
|
||||
};
|
||||
let size = Size::from_bytes(size);
|
||||
|
||||
let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? {
|
||||
let timeout_time = if timeout_ms == this.eval_windows_u32("c", "INFINITE") {
|
||||
None
|
||||
} else {
|
||||
let duration = Duration::from_millis(timeout_ms.into());
|
||||
|
|
@ -325,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
|
||||
this.unblock_thread(self.thread);
|
||||
this.futex_remove_waiter(self.addr, self.thread);
|
||||
let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT")?;
|
||||
let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT");
|
||||
this.set_last_error(error_timeout)?;
|
||||
this.write_scalar(Scalar::from_i32(0), &self.dest)?;
|
||||
|
||||
|
|
@ -377,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?;
|
||||
let flags = this.read_scalar(flags_op)?.to_u32()?;
|
||||
|
||||
let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? {
|
||||
let timeout_time = if timeout_ms == this.eval_windows_u32("c", "INFINITE") {
|
||||
None
|
||||
} else {
|
||||
let duration = Duration::from_millis(timeout_ms.into());
|
||||
|
|
@ -431,9 +431,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
this.condvar_remove_waiter(self.condvar_id, self.thread);
|
||||
|
||||
let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT")?;
|
||||
let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT");
|
||||
this.set_last_error(error_timeout)?;
|
||||
this.write_scalar(this.eval_windows("c", "FALSE")?, &self.dest)?;
|
||||
this.write_scalar(this.eval_windows("c", "FALSE"), &self.dest)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
@ -451,7 +451,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
this.eval_windows("c", "TRUE")
|
||||
Ok(this.eval_windows("c", "TRUE"))
|
||||
}
|
||||
|
||||
fn WakeConditionVariable(&mut self, condvar_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
let stack_size_param_is_a_reservation =
|
||||
this.eval_windows("c", "STACK_SIZE_PARAM_IS_A_RESERVATION")?.to_u32()?;
|
||||
this.eval_windows_u32("c", "STACK_SIZE_PARAM_IS_A_RESERVATION");
|
||||
|
||||
// We ignore the stack size, so we also ignore the
|
||||
// `STACK_SIZE_PARAM_IS_A_RESERVATION` flag.
|
||||
|
|
@ -73,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
_ => this.invalid_handle("WaitForSingleObject")?,
|
||||
};
|
||||
|
||||
if timeout != this.eval_windows("c", "INFINITE")?.to_u32()? {
|
||||
if timeout != this.eval_windows_u32("c", "INFINITE") {
|
||||
throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue