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:
parent
d0ea07e908
commit
f3ae022ed6
6 changed files with 405 additions and 82 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue