Auto merge of #2827 - mojave2:memcpy, r=oli-obk

add `memcpy` and `strcpy` shims
This commit is contained in:
bors 2023-04-12 13:05:11 +00:00
commit fa8e02f634
2 changed files with 118 additions and 0 deletions

View File

@ -744,6 +744,44 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
dest,
)?;
}
"memcpy" => {
let [ptr_dest, ptr_src, n] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
let n = this.read_target_usize(n)?;
this.mem_copy(
ptr_src,
Align::ONE,
ptr_dest,
Align::ONE,
Size::from_bytes(n),
true,
)?;
this.write_pointer(ptr_dest, dest)?;
}
"strcpy" => {
let [ptr_dest, ptr_src] =
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let ptr_dest = this.read_pointer(ptr_dest)?;
let ptr_src = this.read_pointer(ptr_src)?;
// We use `read_c_str` to determine the amount of data to copy,
// and then use `mem_copy` for the actual copy. This means
// pointer provenance is preserved by this implementation of `strcpy`.
// That is probably overly cautious, but there also is no fundamental
// reason to have `strcpy` destroy pointer provenance.
let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap();
this.mem_copy(
ptr_src,
Align::ONE,
ptr_dest,
Align::ONE,
Size::from_bytes(n),
true,
)?;
this.write_pointer(ptr_dest, dest)?;
}
// math functions (note that there are also intrinsics for some other functions)
#[rustfmt::skip]

View File

@ -302,6 +302,83 @@ fn test_posix_mkstemp() {
}
}
fn test_memcpy() {
unsafe {
let src = [1i8, 2, 3];
let dest = libc::calloc(3, 1);
libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
let slc = std::slice::from_raw_parts(dest as *const i8, 3);
assert_eq!(*slc, [1i8, 2, 3]);
libc::free(dest);
}
unsafe {
let src = [1i8, 2, 3];
let dest = libc::calloc(4, 1);
libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
let slc = std::slice::from_raw_parts(dest as *const i8, 4);
assert_eq!(*slc, [1i8, 2, 3, 0]);
libc::free(dest);
}
unsafe {
let src = 123_i32;
let mut dest = 0_i32;
libc::memcpy(
&mut dest as *mut i32 as *mut libc::c_void,
&src as *const i32 as *const libc::c_void,
std::mem::size_of::<i32>(),
);
assert_eq!(dest, src);
}
unsafe {
let src = Some(123);
let mut dest: Option<i32> = None;
libc::memcpy(
&mut dest as *mut Option<i32> as *mut libc::c_void,
&src as *const Option<i32> as *const libc::c_void,
std::mem::size_of::<Option<i32>>(),
);
assert_eq!(dest, src);
}
unsafe {
let src = &123;
let mut dest = &42;
libc::memcpy(
&mut dest as *mut &'static i32 as *mut libc::c_void,
&src as *const &'static i32 as *const libc::c_void,
std::mem::size_of::<&'static i32>(),
);
assert_eq!(*dest, 123);
}
}
fn test_strcpy() {
use std::ffi::{CStr, CString};
// case: src_size equals dest_size
unsafe {
let src = CString::new("rust").unwrap();
let size = src.as_bytes_with_nul().len();
let dest = libc::malloc(size);
libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
libc::free(dest);
}
// case: src_size is less than dest_size
unsafe {
let src = CString::new("rust").unwrap();
let size = src.as_bytes_with_nul().len();
let dest = libc::malloc(size + 1);
libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
libc::free(dest);
}
}
#[cfg(target_os = "linux")]
fn test_sigrt() {
let min = libc::SIGRTMIN();
@ -333,6 +410,9 @@ fn main() {
test_isatty();
test_clocks();
test_memcpy();
test_strcpy();
#[cfg(target_os = "linux")]
{
test_posix_fadvise();