From 67cb5d79edaeb3e1548096b34e4530cfbbd45887 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 23 Nov 2024 11:55:26 +0000 Subject: [PATCH] follow-up on #4052, making a miri evaluation context fn for strerror_r. --- src/shims/unix/android/foreign_items.rs | 9 ---- src/shims/unix/foreign_items.rs | 54 +++++++++++++++++------- src/shims/unix/freebsd/foreign_items.rs | 9 ---- src/shims/unix/linux/foreign_items.rs | 14 +++--- src/shims/unix/macos/foreign_items.rs | 8 ---- src/shims/unix/solarish/foreign_items.rs | 2 +- tests/pass-dep/libc/libc-strerror_r.rs | 16 +++++++ 7 files changed, 62 insertions(+), 50 deletions(-) create mode 100644 tests/pass-dep/libc/libc-strerror_r.rs diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs index 6c5a61437a..80ad40e162 100644 --- a/src/shims/unix/android/foreign_items.rs +++ b/src/shims/unix/android/foreign_items.rs @@ -2,7 +2,6 @@ use rustc_abi::ExternAbi; use rustc_span::Symbol; use crate::shims::unix::android::thread::prctl; -use crate::shims::unix::foreign_items::EvalContextExt as _; use crate::shims::unix::linux::syscall::syscall; use crate::*; @@ -21,14 +20,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { - // Querying system information - "sysconf" => { - let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let result = this.sysconf(val)?; - this.write_scalar(result, dest)?; - } - // Miscellaneous "__errno" => { let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index a50ac1be77..5594bd4e79 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -68,6 +68,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("unimplemented sysconf name: {}", name) } + fn strerror_r( + &mut self, + errnum: &OpTy<'tcx>, + buf: &OpTy<'tcx>, + buflen: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let errnum = this.read_scalar(errnum)?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_target_usize(buflen)?; + let error = this.try_errnum_to_io_error(errnum)?; + let formatted = match error { + Some(err) => format!("{err}"), + None => format!(""), + }; + let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; + if complete { + interp_ok(Scalar::from_i32(0)) + } else { + interp_ok(Scalar::from_i32(this.eval_libc_i32("ERANGE"))) + } + } + fn emulate_foreign_item_inner( &mut self, link_name: Symbol, @@ -113,6 +137,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } + "sysconf" => { + let [val] = + this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let result = this.sysconf(val)?; + this.write_scalar(result, dest)?; + } + // File descriptors "read" => { let [fd, buf, count] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; @@ -724,21 +755,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } - "strerror_r" | "__xpg_strerror_r" => { - let [errnum, buf, buflen] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let errnum = this.read_scalar(errnum)?; - let buf = this.read_pointer(buf)?; - let buflen = this.read_target_usize(buflen)?; - - let error = this.try_errnum_to_io_error(errnum)?; - let formatted = match error { - Some(err) => format!("{err}"), - None => format!(""), - }; - 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") }; - this.write_int(ret, dest)?; - } "getentropy" => { // This function is non-standard but exists with the same signature and behavior on // Linux, macOS, FreeBSD and Solaris/Illumos. @@ -766,6 +782,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } } + + "strerror_r" => { + let [errnum, buf, buflen] = + this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let result = this.strerror_r(errnum, buf, buflen)?; + this.write_scalar(result, dest)?; + } + "getrandom" => { // This function is non-standard but exists with the same signature and behavior on // Linux, FreeBSD and Solaris/Illumos. diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index ddea9ecc29..1346d8de7e 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -1,7 +1,6 @@ use rustc_abi::ExternAbi; use rustc_span::Symbol; -use crate::shims::unix::foreign_items::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -76,14 +75,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } - // Querying system information - "sysconf" => { - let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let result = this.sysconf(val)?; - this.write_scalar(result, dest)?; - } - // Miscellaneous "__error" => { let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 75b0afcac0..810e8d3340 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -125,14 +125,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } - // Querying system information - "sysconf" => { - let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let result = this.sysconf(val)?; - this.write_scalar(result, dest)?; - } - // Dynamically invoked syscalls "syscall" => { syscall(this, link_name, abi, args, dest)?; @@ -152,6 +144,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ptr = this.mremap(old_address, old_size, new_size, flags)?; this.write_scalar(ptr, dest)?; } + "__xpg_strerror_r" => { + let [errnum, buf, buflen] = + this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; + let result = this.strerror_r(errnum, buf, buflen)?; + this.write_scalar(result, dest)?; + } "__errno_location" => { let [] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 7f67a2cab3..003025916c 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -2,7 +2,6 @@ use rustc_abi::ExternAbi; use rustc_span::Symbol; use super::sync::EvalContextExt as _; -use crate::shims::unix::foreign_items::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -168,13 +167,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(stack_size, dest)?; } - "sysconf" => { - let [val] = - this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; - let result = this.sysconf(val)?; - this.write_scalar(result, dest)?; - } - // Threading "pthread_setname_np" => { let [name] = diff --git a/src/shims/unix/solarish/foreign_items.rs b/src/shims/unix/solarish/foreign_items.rs index 2eeab38e35..1bbd25617e 100644 --- a/src/shims/unix/solarish/foreign_items.rs +++ b/src/shims/unix/solarish/foreign_items.rs @@ -113,7 +113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - "sysconf" | "__sysconf_xpg7" => { + "__sysconf_xpg7" => { let [val] = this.check_shim(abi, ExternAbi::C { unwind: false }, link_name, args)?; let result = this.sysconf(val)?; diff --git a/tests/pass-dep/libc/libc-strerror_r.rs b/tests/pass-dep/libc/libc-strerror_r.rs new file mode 100644 index 0000000000..09885ce839 --- /dev/null +++ b/tests/pass-dep/libc/libc-strerror_r.rs @@ -0,0 +1,16 @@ +//@ignore-target: windows # Supported only on unixes + +fn main() { + unsafe { + let mut buf = vec![0u8; 32]; + assert_eq!(libc::strerror_r(libc::EPERM, buf.as_mut_ptr().cast(), buf.len()), 0); + let mut buf2 = vec![0u8; 64]; + assert_eq!(libc::strerror_r(-1i32, buf2.as_mut_ptr().cast(), buf2.len()), 0); + // This buffer is deliberately too small so this triggers ERANGE. + let mut buf3 = vec![0u8; 2]; + assert_eq!( + libc::strerror_r(libc::E2BIG, buf3.as_mut_ptr().cast(), buf3.len()), + libc::ERANGE + ); + } +}