diff options
| author | mojave2 <0109chenchen@gmail.com> | 2023-04-11 16:39:24 +0800 |
|---|---|---|
| committer | mojave2 <0109chenchen@gmail.com> | 2023-04-12 20:46:12 +0800 |
| commit | aacd261e00e83d70ddb0b98b54fb03ed027b33cc (patch) | |
| tree | e2738c893c275b62744bf8c99bdf13ae0b029b3c /src | |
| parent | dedac2d5e2ec863b65cf4adb34b7804becf140f8 (diff) | |
| download | rust-aacd261e00e83d70ddb0b98b54fb03ed027b33cc.tar.gz rust-aacd261e00e83d70ddb0b98b54fb03ed027b33cc.zip | |
add memcpy/strcpy shims
add memcpy/strcpy/strncpy shims fix bug add memcpy/strcpy/strncpy shims add a test for strncpy remove strncpy shim
Diffstat (limited to 'src')
| -rw-r--r-- | src/tools/miri/src/shims/foreign_items.rs | 38 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass-dep/shims/libc-misc.rs | 80 |
2 files changed, 118 insertions, 0 deletions
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index fcee381ff71..3aeaffe6ad0 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -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 properly 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] diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs index 6fffbc9b4ac..8be9cd983a7 100644 --- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs @@ -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(); |
