Skip to content

Commit 510d727

Browse files
committed
Auto merge of #2827 - mojave2:memcpy, r=oli-obk
add `memcpy` and `strcpy` shims
2 parents 357458c + 3c28e30 commit 510d727

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

src/shims/foreign_items.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,6 +744,44 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
744744
dest,
745745
)?;
746746
}
747+
"memcpy" => {
748+
let [ptr_dest, ptr_src, n] =
749+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
750+
let ptr_dest = this.read_pointer(ptr_dest)?;
751+
let ptr_src = this.read_pointer(ptr_src)?;
752+
let n = this.read_target_usize(n)?;
753+
this.mem_copy(
754+
ptr_src,
755+
Align::ONE,
756+
ptr_dest,
757+
Align::ONE,
758+
Size::from_bytes(n),
759+
true,
760+
)?;
761+
this.write_pointer(ptr_dest, dest)?;
762+
}
763+
"strcpy" => {
764+
let [ptr_dest, ptr_src] =
765+
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
766+
let ptr_dest = this.read_pointer(ptr_dest)?;
767+
let ptr_src = this.read_pointer(ptr_src)?;
768+
769+
// We use `read_c_str` to determine the amount of data to copy,
770+
// and then use `mem_copy` for the actual copy. This means
771+
// pointer provenance is preserved by this implementation of `strcpy`.
772+
// That is probably overly cautious, but there also is no fundamental
773+
// reason to have `strcpy` destroy pointer provenance.
774+
let n = this.read_c_str(ptr_src)?.len().checked_add(1).unwrap();
775+
this.mem_copy(
776+
ptr_src,
777+
Align::ONE,
778+
ptr_dest,
779+
Align::ONE,
780+
Size::from_bytes(n),
781+
true,
782+
)?;
783+
this.write_pointer(ptr_dest, dest)?;
784+
}
747785

748786
// math functions (note that there are also intrinsics for some other functions)
749787
#[rustfmt::skip]

tests/pass-dep/shims/libc-misc.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,83 @@ fn test_posix_mkstemp() {
302302
}
303303
}
304304

305+
fn test_memcpy() {
306+
unsafe {
307+
let src = [1i8, 2, 3];
308+
let dest = libc::calloc(3, 1);
309+
libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
310+
let slc = std::slice::from_raw_parts(dest as *const i8, 3);
311+
assert_eq!(*slc, [1i8, 2, 3]);
312+
libc::free(dest);
313+
}
314+
315+
unsafe {
316+
let src = [1i8, 2, 3];
317+
let dest = libc::calloc(4, 1);
318+
libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
319+
let slc = std::slice::from_raw_parts(dest as *const i8, 4);
320+
assert_eq!(*slc, [1i8, 2, 3, 0]);
321+
libc::free(dest);
322+
}
323+
324+
unsafe {
325+
let src = 123_i32;
326+
let mut dest = 0_i32;
327+
libc::memcpy(
328+
&mut dest as *mut i32 as *mut libc::c_void,
329+
&src as *const i32 as *const libc::c_void,
330+
std::mem::size_of::<i32>(),
331+
);
332+
assert_eq!(dest, src);
333+
}
334+
335+
unsafe {
336+
let src = Some(123);
337+
let mut dest: Option<i32> = None;
338+
libc::memcpy(
339+
&mut dest as *mut Option<i32> as *mut libc::c_void,
340+
&src as *const Option<i32> as *const libc::c_void,
341+
std::mem::size_of::<Option<i32>>(),
342+
);
343+
assert_eq!(dest, src);
344+
}
345+
346+
unsafe {
347+
let src = &123;
348+
let mut dest = &42;
349+
libc::memcpy(
350+
&mut dest as *mut &'static i32 as *mut libc::c_void,
351+
&src as *const &'static i32 as *const libc::c_void,
352+
std::mem::size_of::<&'static i32>(),
353+
);
354+
assert_eq!(*dest, 123);
355+
}
356+
}
357+
358+
fn test_strcpy() {
359+
use std::ffi::{CStr, CString};
360+
361+
// case: src_size equals dest_size
362+
unsafe {
363+
let src = CString::new("rust").unwrap();
364+
let size = src.as_bytes_with_nul().len();
365+
let dest = libc::malloc(size);
366+
libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
367+
assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
368+
libc::free(dest);
369+
}
370+
371+
// case: src_size is less than dest_size
372+
unsafe {
373+
let src = CString::new("rust").unwrap();
374+
let size = src.as_bytes_with_nul().len();
375+
let dest = libc::malloc(size + 1);
376+
libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
377+
assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
378+
libc::free(dest);
379+
}
380+
}
381+
305382
#[cfg(target_os = "linux")]
306383
fn test_sigrt() {
307384
let min = libc::SIGRTMIN();
@@ -333,6 +410,9 @@ fn main() {
333410
test_isatty();
334411
test_clocks();
335412

413+
test_memcpy();
414+
test_strcpy();
415+
336416
#[cfg(target_os = "linux")]
337417
{
338418
test_posix_fadvise();

0 commit comments

Comments
 (0)