replaced check_shim with check_shim_abi for env, file, sockets and time related shims

Making type consistent in shims

pread return type fix

make clock_gettime shim type consistent
This commit is contained in:
geetanshjuneja 2025-04-10 13:32:04 +05:30
parent d0ea07e908
commit f3ae022ed6
6 changed files with 405 additions and 82 deletions

View file

@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
}
/// Check that the given `caller_fn_abi` matches the expected ABI described by
/// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and the return the list of
/// `callee_abi`, `callee_input_tys`, `callee_output_ty`, and then returns the list of
/// arguments.
fn check_shim_abi<'a, const N: usize>(
&mut self,

View file

@ -21,7 +21,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
&mut self,
clk_id_op: &OpTy<'tcx>,
tp_op: &OpTy<'tcx>,
) -> InterpResult<'tcx, Scalar> {
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
// This clock support is deliberately minimal because a lot of clock types have fiddly
// properties (is it possible for Miri to be suspended independently of the host?). If you
// have a use for another clock type, please open an issue.
@ -29,8 +30,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let this = self.eval_context_mut();
this.assert_target_os_is_unix("clock_gettime");
let clockid_t_size = this.libc_ty_layout("clockid_t").size;
let clk_id = this.read_scalar(clk_id_op)?.to_i32()?;
let clk_id = this.read_scalar(clk_id_op)?.to_int(clockid_t_size)?;
let tp = this.deref_pointer_as(tp_op, this.libc_ty_layout("timespec"))?;
let absolute_clocks;
@ -43,34 +45,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'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("CLOCK_REALTIME").to_int(clockid_t_size)?,
this.eval_libc("CLOCK_REALTIME_COARSE").to_int(clockid_t_size)?,
];
// 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 additional 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("CLOCK_MONOTONIC").to_int(clockid_t_size)?,
this.eval_libc("CLOCK_MONOTONIC_COARSE").to_int(clockid_t_size)?,
];
}
"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("CLOCK_REALTIME").to_int(clockid_t_size)?];
relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
// `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("CLOCK_UPTIME_RAW").to_int(clockid_t_size)?);
}
"solaris" | "illumos" => {
// The REALTIME clock returns the actual time since the Unix epoch.
absolute_clocks = vec![this.eval_libc_i32("CLOCK_REALTIME")];
absolute_clocks = vec![this.eval_libc("CLOCK_REALTIME").to_int(clockid_t_size)?];
// MONOTONIC, in the other hand, is the high resolution, non-adjustable
// clock from an arbitrary time in the past.
// Note that the man page mentions HIGHRES but it is just
// an alias of MONOTONIC and the libc crate does not expose it anyway.
// https://docs.oracle.com/cd/E23824_01/html/821-1465/clock-gettime-3c.html
relative_clocks = vec![this.eval_libc_i32("CLOCK_MONOTONIC")];
relative_clocks = vec![this.eval_libc("CLOCK_MONOTONIC").to_int(clockid_t_size)?];
}
target => throw_unsup_format!("`clock_gettime` is not supported on target OS {target}"),
}
@ -81,15 +83,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
} else if relative_clocks.contains(&clk_id) {
this.machine.monotonic_clock.now().duration_since(this.machine.monotonic_clock.epoch())
} else {
return this.set_last_error_and_return_i32(LibcError("EINVAL"));
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
};
let tv_sec = duration.as_secs();
let tv_nsec = duration.subsec_nanos();
this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &tp)?;
this.write_int(0, dest)?;
interp_ok(Scalar::from_i32(0))
interp_ok(())
}
fn gettimeofday(

View file

@ -112,51 +112,122 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
match link_name.as_str() {
// Environment related shims
"getenv" => {
let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
let [name] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.getenv(name)?;
this.write_pointer(result, dest)?;
}
"unsetenv" => {
let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
let [name] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.unsetenv(name)?;
this.write_scalar(result, dest)?;
}
"setenv" => {
let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?;
let [name, value, overwrite] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.machine.layouts.const_raw_ptr.ty,
this.machine.layouts.const_raw_ptr.ty,
this.tcx.types.i32,
],
this.tcx.types.i32,
args,
)?;
this.read_scalar(overwrite)?.to_i32()?;
let result = this.setenv(name, value)?;
this.write_scalar(result, dest)?;
}
"getcwd" => {
let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?;
let [buf, size] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.getcwd(buf, size)?;
this.write_pointer(result, dest)?;
}
"chdir" => {
let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
let [path] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.chdir(path)?;
this.write_scalar(result, dest)?;
}
"getpid" => {
let [] = this.check_shim(abi, Conv::C, link_name, args)?;
let [] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[],
this.libc_ty_layout("pid_t").ty,
args,
)?;
let result = this.getpid()?;
this.write_scalar(result, dest)?;
}
"sysconf" => {
let [val] = this.check_shim(abi, Conv::C, link_name, args)?;
let [val] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32],
this.tcx.types.isize,
args,
)?;
let result = this.sysconf(val)?;
this.write_scalar(result, dest)?;
}
// File descriptors
"read" => {
let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd, buf, count] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.usize],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
this.read(fd, buf, count, None, dest)?;
}
"write" => {
let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd, buf, n] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.machine.layouts.const_raw_ptr.ty,
this.tcx.types.usize,
],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
@ -164,38 +235,88 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write(fd, buf, count, None, dest)?;
}
"pread" => {
let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
let off_t = this.libc_ty_layout("off_t");
let [fd, buf, count, offset] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.machine.layouts.mut_raw_ptr.ty,
this.tcx.types.usize,
off_t.ty,
],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite" => {
let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
let off_t = this.libc_ty_layout("off_t");
let [fd, buf, n, offset] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.machine.layouts.const_raw_ptr.ty,
this.tcx.types.usize,
off_t.ty,
],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
trace!("Called pwrite({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
this.write(fd, buf, count, Some(offset), dest)?;
}
"pread64" => {
let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
let off64_t = this.libc_ty_layout("off64_t");
let [fd, buf, count, offset] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.machine.layouts.mut_raw_ptr.ty,
this.tcx.types.usize,
off64_t.ty,
],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(count)?;
let offset =
this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
this.read(fd, buf, count, Some(offset), dest)?;
}
"pwrite64" => {
let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?;
let off64_t = this.libc_ty_layout("off64_t");
let [fd, buf, n, offset] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.machine.layouts.const_raw_ptr.ty,
this.tcx.types.usize,
off64_t.ty,
],
this.tcx.types.isize,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let buf = this.read_pointer(buf)?;
let count = this.read_target_usize(n)?;
let offset =
this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?;
let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset);
this.write(fd, buf, count, Some(offset), dest)?;
}
@ -218,13 +339,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(result, dest)?;
}
"dup" => {
let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [old_fd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.dup(old_fd)?;
this.write_scalar(new_fd, dest)?;
}
"dup2" => {
let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [old_fd, new_fd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let old_fd = this.read_scalar(old_fd)?.to_i32()?;
let new_fd = this.read_scalar(new_fd)?.to_i32()?;
let result = this.dup2(old_fd, new_fd)?;
@ -233,7 +368,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"flock" => {
// Currently this function does not exist on all Unixes, e.g. on Solaris.
this.check_target_os(&["linux", "freebsd", "macos", "illumos"], link_name)?;
let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd, op] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let op = this.read_scalar(op)?.to_i32()?;
let result = this.flock(fd, op)?;
@ -250,140 +392,311 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
this.write_scalar(result, dest)?;
}
"unlink" => {
let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
let [path] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.unlink(path)?;
this.write_scalar(result, dest)?;
}
"symlink" => {
let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?;
let [target, linkpath] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.symlink(target, linkpath)?;
this.write_scalar(result, dest)?;
}
"rename" => {
let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?;
let [oldpath, newpath] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.rename(oldpath, newpath)?;
this.write_scalar(result, dest)?;
}
"mkdir" => {
let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?;
let [path, mode] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty, this.libc_ty_layout("mode_t").ty],
this.tcx.types.i32,
args,
)?;
let result = this.mkdir(path, mode)?;
this.write_scalar(result, dest)?;
}
"rmdir" => {
let [path] = this.check_shim(abi, Conv::C, link_name, args)?;
let [path] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.rmdir(path)?;
this.write_scalar(result, dest)?;
}
"opendir" => {
let [name] = this.check_shim(abi, Conv::C, link_name, args)?;
let [name] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty],
this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.opendir(name)?;
this.write_scalar(result, dest)?;
}
"closedir" => {
let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?;
let [dirp] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.closedir(dirp)?;
this.write_scalar(result, dest)?;
}
"lseek64" => {
let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
let off64_t = this.libc_ty_layout("off64_t");
let [fd, offset, whence] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, off64_t.ty, this.tcx.types.i32],
off64_t.ty,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_scalar(offset)?.to_i64()?;
let offset = this.read_scalar(offset)?.to_int(off64_t.size)?;
let whence = this.read_scalar(whence)?.to_i32()?;
let result = this.lseek64(fd, offset.into(), whence)?;
this.write_scalar(result, dest)?;
this.lseek64(fd, offset, whence, dest)?;
}
"lseek" => {
let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?;
let off_t = this.libc_ty_layout("off_t");
let [fd, offset, whence] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, off_t.ty, this.tcx.types.i32],
off_t.ty,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?;
let offset = this.read_scalar(offset)?.to_int(off_t.size)?;
let whence = this.read_scalar(whence)?.to_i32()?;
let result = this.lseek64(fd, offset, whence)?;
this.write_scalar(result, dest)?;
this.lseek64(fd, offset, whence, dest)?;
}
"ftruncate64" => {
let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
let off64_t = this.libc_ty_layout("off64_t");
let [fd, length] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, off64_t.ty],
this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_i64()?;
let result = this.ftruncate64(fd, length.into())?;
let length = this.read_scalar(length)?.to_int(off64_t.size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"ftruncate" => {
let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?;
let off_t = this.libc_ty_layout("off_t");
let [fd, length] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, off_t.ty],
this.tcx.types.i32,
args,
)?;
let fd = this.read_scalar(fd)?.to_i32()?;
let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?;
let length = this.read_scalar(length)?.to_int(off_t.size)?;
let result = this.ftruncate64(fd, length)?;
this.write_scalar(result, dest)?;
}
"fsync" => {
let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let result = this.fsync(fd)?;
this.write_scalar(result, dest)?;
}
"fdatasync" => {
let [fd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [fd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let result = this.fdatasync(fd)?;
this.write_scalar(result, dest)?;
}
"readlink" => {
let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?;
let [pathname, buf, bufsize] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.machine.layouts.const_raw_ptr.ty,
this.machine.layouts.mut_raw_ptr.ty,
this.tcx.types.usize,
],
this.tcx.types.isize,
args,
)?;
let result = this.readlink(pathname, buf, bufsize)?;
this.write_scalar(Scalar::from_target_isize(result, this), dest)?;
}
"posix_fadvise" => {
let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?;
let off_t = this.libc_ty_layout("off_t");
let [fd, offset, len, advice] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.tcx.types.i32, off_t.ty, off_t.ty, this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
this.read_scalar(fd)?.to_i32()?;
this.read_target_isize(offset)?;
this.read_target_isize(len)?;
this.read_scalar(offset)?.to_int(off_t.size)?;
this.read_scalar(len)?.to_int(off_t.size)?;
this.read_scalar(advice)?.to_i32()?;
// fadvise is only informational, we can ignore it.
this.write_null(dest)?;
}
"realpath" => {
let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?;
let [path, resolved_path] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.realpath(path, resolved_path)?;
this.write_scalar(result, dest)?;
}
"mkstemp" => {
let [template] = this.check_shim(abi, Conv::C, link_name, args)?;
let [template] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.mkstemp(template)?;
this.write_scalar(result, dest)?;
}
// Unnamed sockets and pipes
"socketpair" => {
let [domain, type_, protocol, sv] =
this.check_shim(abi, Conv::C, link_name, args)?;
let [domain, type_, protocol, sv] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[
this.tcx.types.i32,
this.tcx.types.i32,
this.tcx.types.i32,
this.machine.layouts.mut_raw_ptr.ty,
],
this.tcx.types.i32,
args,
)?;
let result = this.socketpair(domain, type_, protocol, sv)?;
this.write_scalar(result, dest)?;
}
"pipe" => {
let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?;
let [pipefd] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.pipe2(pipefd, /*flags*/ None)?;
this.write_scalar(result, dest)?;
}
"pipe2" => {
// Currently this function does not exist on all Unixes, e.g. on macOS.
this.check_target_os(&["linux", "freebsd", "solaris", "illumos"], link_name)?;
let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?;
let [pipefd, flags] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty, this.tcx.types.i32],
this.tcx.types.i32,
args,
)?;
let result = this.pipe2(pipefd, Some(flags))?;
this.write_scalar(result, dest)?;
}
// Time
"gettimeofday" => {
let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?;
let [tv, tz] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.mut_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
let result = this.gettimeofday(tv, tz)?;
this.write_scalar(result, dest)?;
}
"localtime_r" => {
let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?;
let [timep, result_op] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.machine.layouts.const_raw_ptr.ty, this.machine.layouts.mut_raw_ptr.ty],
this.machine.layouts.mut_raw_ptr.ty,
args,
)?;
let result = this.localtime_r(timep, result_op)?;
this.write_pointer(result, dest)?;
}
"clock_gettime" => {
let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?;
let result = this.clock_gettime(clk_id, tp)?;
this.write_scalar(result, dest)?;
let [clk_id, tp] = this.check_shim_abi(
link_name,
abi,
ExternAbi::C { unwind: false },
[this.libc_ty_layout("clockid_t").ty, this.machine.layouts.mut_raw_ptr.ty],
this.tcx.types.i32,
args,
)?;
this.clock_gettime(clk_id, tp, dest)?;
}
// Allocation
@ -834,7 +1147,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
// These shims are enabled only when the caller is in the standard library.
"pthread_attr_getguardsize" if this.frame_in_std() => {
let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?;
let guard_size_layout = this.libc_ty_layout("size_t");
let guard_size_layout = this.machine.layouts.usize;
let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?;
this.write_scalar(
Scalar::from_uint(this.machine.page_size, guard_size_layout.size),

View file

@ -502,7 +502,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
interp_ok(Scalar::from_i32(this.try_unwrap_io_result(fd)?))
}
fn lseek64(&mut self, fd_num: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> {
fn lseek64(
&mut self,
fd_num: i32,
offset: i128,
whence: i32,
dest: &MPlaceTy<'tcx>,
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
// Isolation check is done via `FileDescription` trait.
@ -510,7 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
let seek_from = if whence == this.eval_libc_i32("SEEK_SET") {
if offset < 0 {
// Negative offsets return `EINVAL`.
return this.set_last_error_and_return_i64(LibcError("EINVAL"));
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
} else {
SeekFrom::Start(u64::try_from(offset).unwrap())
}
@ -519,19 +525,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
} else if whence == this.eval_libc_i32("SEEK_END") {
SeekFrom::End(i64::try_from(offset).unwrap())
} else {
return this.set_last_error_and_return_i64(LibcError("EINVAL"));
return this.set_last_error_and_return(LibcError("EINVAL"), dest);
};
let communicate = this.machine.communicate();
let Some(fd) = this.machine.fds.get(fd_num) else {
return this.set_last_error_and_return_i64(LibcError("EBADF"));
return this.set_last_error_and_return(LibcError("EBADF"), dest);
};
let result = fd.seek(communicate, seek_from)?.map(|offset| i64::try_from(offset).unwrap());
drop(fd);
let result = this.try_unwrap_io_result(result)?;
interp_ok(Scalar::from_i64(result))
this.write_int(result, dest)?;
interp_ok(())
}
fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> {

View file

@ -9,6 +9,6 @@ extern "C" {
fn main() {
let mut fds = [-1, -1];
let res = unsafe { pipe(fds.as_mut_ptr()) };
//~^ ERROR: calling a non-variadic function with a variadic caller-side signature
//~^ ERROR: ABI mismatch: calling a non-variadic function with a variadic caller-side signature
assert_eq!(res, 0);
}

View file

@ -1,8 +1,8 @@
error: Undefined Behavior: calling a non-variadic function with a variadic caller-side signature
error: Undefined Behavior: ABI mismatch: calling a non-variadic function with a variadic caller-side signature
--> tests/fail/shims/vararg_caller_signature_mismatch.rs:LL:CC
|
LL | let res = unsafe { pipe(fds.as_mut_ptr()) };
| ^^^^^^^^^^^^^^^^^^^^^^ calling a non-variadic function with a variadic caller-side signature
| ^^^^^^^^^^^^^^^^^^^^^^ ABI mismatch: calling a non-variadic function with a variadic caller-side signature
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information