diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index 2ccc150e..e7152279 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use std::ops::Deref; use std::rc::Rc; -use crate::rc::{AnyPtr, ErasedPtr}; +use crate::rc::{AnyPtr, ErasedPtr, Ptr}; use crate::reinterpret::ByteRepr; pub trait FnAddr { @@ -146,20 +146,14 @@ impl Eq for FnPtr {} impl ByteRepr for FnPtr {} impl ErasedPtr for FnPtr { - fn pointee_type_id(&self) -> TypeId { - TypeId::of::() - } - fn memcpy(&self, _src: &dyn ErasedPtr, _len: usize) { - panic!("memcpy not supported on fn pointer"); + fn as_bytes(&self) -> Ptr { + panic!("byte view not supported on fn pointer"); } fn as_any(&self) -> &dyn Any { self } - fn equals(&self, other: &dyn ErasedPtr) -> Option { - if self.pointee_type_id() != other.pointee_type_id() { - return None; - } - other.as_any().downcast_ref::>().map(|o| self == o) + fn equals(&self, other: &dyn ErasedPtr) -> bool { + other.as_any().downcast_ref::>() == Some(self) } fn is_null(&self) -> bool { FnPtr::is_null(self) diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index ac09c80c..ce8bf501 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -1042,49 +1042,33 @@ impl Ptr { } pub(crate) trait ErasedPtr: std::any::Any { - fn pointee_type_id(&self) -> std::any::TypeId; - fn memcpy(&self, src: &dyn ErasedPtr, len: usize); + fn as_bytes(&self) -> Ptr; fn as_any(&self) -> &dyn std::any::Any; - fn equals(&self, other: &dyn ErasedPtr) -> Option; + fn equals(&self, other: &dyn ErasedPtr) -> bool; fn is_null(&self) -> bool; } +impl PartialEq for dyn ErasedPtr { + fn eq(&self, other: &Self) -> bool { + self.equals(other) + } +} + impl ErasedPtr for Ptr where T: ByteRepr + 'static, Ptr: PartialEq, { - fn pointee_type_id(&self) -> std::any::TypeId { - std::any::TypeId::of::() - } - - fn memcpy(&self, src: &dyn ErasedPtr, len: usize) { - if self.pointee_type_id() != src.pointee_type_id() { - panic!("memcpy: type mismatch"); - } - let src_ptr = src - .as_any() - .downcast_ref::>() - .expect("memcpy: downcast to Ptr failed"); - let dst_bytes: Ptr = self.reinterpret_cast(); - let src_bytes: Ptr = src_ptr.reinterpret_cast(); - dst_bytes.memcpy(&src_bytes, len); + fn as_bytes(&self) -> Ptr { + self.reinterpret_cast::() } fn as_any(&self) -> &dyn std::any::Any { self } - fn equals(&self, other: &dyn ErasedPtr) -> Option { - if self.pointee_type_id() != other.pointee_type_id() { - return None; - } - - if let Some(other_ptr) = other.as_any().downcast_ref::>() { - return Some(self == other_ptr); - } - - None + fn equals(&self, other: &dyn ErasedPtr) -> bool { + other.as_any().downcast_ref::>() == Some(self) } fn is_null(&self) -> bool { @@ -1118,66 +1102,28 @@ impl AnyPtr { } self.ptr.as_any().downcast_ref::>().cloned() } - - pub fn reinterpret_cast(&self) -> Ptr { - macro_rules! try_src { - ($ty:ty) => {{ - if let Some(p) = self.cast::<$ty>() { - return p.reinterpret_cast::(); - } - if let Some(pv) = self.cast::>() { - return pv.reinterpret_cast::(); - } - }}; - } - - try_src!(u8); - try_src!(i8); - try_src!(u16); - try_src!(i16); - try_src!(u32); - try_src!(i32); - try_src!(u64); - try_src!(i64); - try_src!(usize); - try_src!(isize); - - panic!("reinterpret_cast: unsupported AnyPtr source"); - } } impl PartialEq for AnyPtr { fn eq(&self, other: &Self) -> bool { - let lhs: &dyn ErasedPtr = self.ptr.as_ref(); - let rhs: &dyn ErasedPtr = other.ptr.as_ref(); - - lhs.equals(rhs).unwrap_or_default() + *self.ptr == *other.ptr } } impl AnyPtr { pub fn memcpy(&self, src: &AnyPtr, len: usize) { - let dst_erased = &*self.ptr; - let src_erased = &*src.ptr; - - if dst_erased.pointee_type_id() == src_erased.pointee_type_id() { - dst_erased.memcpy(src_erased, len); - return; - } - - let dst_u8: Ptr = self.reinterpret_cast(); - let src_u8: Ptr = src.reinterpret_cast(); + let dst_u8 = self.ptr.as_bytes(); + let src_u8 = src.ptr.as_bytes(); dst_u8.memcpy(&src_u8, len); } pub fn memset(&self, value: u8, num: usize) { - let dst_u8: Ptr = self.reinterpret_cast(); - dst_u8.memset(value, num); + self.ptr.as_bytes().memset(value, num); } pub fn memcmp(&self, other: &AnyPtr, len: usize) -> i32 { - let a: Ptr = self.reinterpret_cast(); - let b: Ptr = other.reinterpret_cast(); + let a = self.ptr.as_bytes(); + let b = other.ptr.as_bytes(); a.memcmp(&b, len) } } diff --git a/tests/unit/memcpy_struct_bytes.c b/tests/unit/memcpy_struct_bytes.c new file mode 100644 index 00000000..ae767639 --- /dev/null +++ b/tests/unit/memcpy_struct_bytes.c @@ -0,0 +1,23 @@ +#include +#include +#include + +struct point { + int32_t x; + int32_t y; +}; + +int main(void) { + struct point src = {3, 7}; + + unsigned char buf[sizeof(struct point)]; + memcpy(buf, &src, sizeof(buf)); + + struct point dst; + memcpy(&dst, buf, sizeof(dst)); + + assert(dst.x == 3); + assert(dst.y == 7); + + return 0; +} diff --git a/tests/unit/out/refcount/memcpy_struct_bytes.rs b/tests/unit/out/refcount/memcpy_struct_bytes.rs new file mode 100644 index 00000000..d233b346 --- /dev/null +++ b/tests/unit/out/refcount/memcpy_struct_bytes.rs @@ -0,0 +1,58 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct point { + pub x: Value, + pub y: Value, +} +impl ByteRepr for point { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let src: Value = Rc::new(RefCell::new(point { + x: Rc::new(RefCell::new(3)), + y: Rc::new(RefCell::new(7)), + })); + let buf: Value> = Rc::new(RefCell::new( + (0..8).map(|_| ::default()).collect::>(), + )); + { + ((buf.as_pointer() as Ptr) as Ptr).to_any().memcpy( + &((src.as_pointer()) as Ptr).to_any(), + ::std::mem::size_of::<[u8; 8]>() as usize, + ); + ((buf.as_pointer() as Ptr) as Ptr).to_any().clone() + }; + let dst: Value = >::default(); + { + ((dst.as_pointer()) as Ptr).to_any().memcpy( + &((buf.as_pointer() as Ptr) as Ptr).to_any(), + 8usize as usize, + ); + ((dst.as_pointer()) as Ptr).to_any().clone() + }; + assert!(((((*(*dst.borrow()).x.borrow()) == 3) as i32) != 0)); + assert!(((((*(*dst.borrow()).y.borrow()) == 7) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/memcpy_struct_bytes.rs b/tests/unit/out/unsafe/memcpy_struct_bytes.rs new file mode 100644 index 00000000..110b0a87 --- /dev/null +++ b/tests/unit/out/unsafe/memcpy_struct_bytes.rs @@ -0,0 +1,47 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct point { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut src: point = point { x: 3, y: 7 }; + let mut buf: [u8; 8] = [0_u8; 8]; + { + if ::std::mem::size_of::<[u8; 8]>() != 0 { + ::std::ptr::copy_nonoverlapping( + ((&mut src as *mut point) as *const point as *const ::libc::c_void), + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void), + ::std::mem::size_of::<[u8; 8]>() as usize, + ) + } + (buf.as_mut_ptr() as *mut u8 as *mut ::libc::c_void) + }; + let mut dst: point = ::default(); + { + if ::std::mem::size_of::() != 0 { + ::std::ptr::copy_nonoverlapping( + (buf.as_mut_ptr() as *const u8 as *const ::libc::c_void), + ((&mut dst as *mut point) as *mut point as *mut ::libc::c_void), + ::std::mem::size_of::() as usize, + ) + } + ((&mut dst as *mut point) as *mut point as *mut ::libc::c_void) + }; + assert!(((((dst.x) == (3)) as i32) != 0)); + assert!(((((dst.y) == (7)) as i32) != 0)); + return 0; +}