Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -503,10 +503,13 @@ void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) {
{
PushBrace impl_brace(*this);
for (auto *field : decl->fields()) {
PushConversionKind push(*this, ConversionKind::FullRefCount);
std::string storage_ty = ToString(field->getType());
Unwrap(storage_ty, "Value<", ">");
StrCat(std::format(
"pub fn {}(&self) -> Ptr<{}> {{ (self.__bytes.as_pointer() "
"as Ptr<u8>).reinterpret_cast() }}",
GetNamedDeclAsString(field), Mapper::Map(field->getType())));
GetNamedDeclAsString(field), storage_ty));
}
}

Expand Down Expand Up @@ -1299,9 +1302,17 @@ bool ConverterRefCount::VisitExplicitCastExpr(clang::ExplicitCastExpr *expr) {
} else if (expr->getSubExpr()->getType()->isPointerType() &&
!expr->getSubExpr()->isNullPointerConstant(
ctx_, clang::Expr::NPC_ValueDependentIsNull)) {
StrCat(std::format("({}.to_strong().as_pointer() as {})",
ToString(expr->getSubExpr()),
ToString(expr->getType())));
auto src_pointee = expr->getSubExpr()->getType()->getPointeeType();
auto dst_pointee = expr->getType()->getPointeeType();
if (ctx_.hasSameUnqualifiedType(src_pointee, dst_pointee)) {
StrCat(std::format("({}.to_strong().as_pointer() as {})",
ToString(expr->getSubExpr()),
ToString(expr->getType())));
} else {
StrCat(std::format("{}.reinterpret_cast::<{}>()",
ToString(expr->getSubExpr()),
ConvertPointeeType(expr->getType())));
}
return false;
}
return Converter::VisitExplicitCastExpr(expr);
Expand Down Expand Up @@ -1488,6 +1499,7 @@ bool ConverterRefCount::VisitInitListExpr(clang::InitListExpr *expr) {
}

void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) {
auto member = expr->getMemberDecl();
std::string str;
{
Buffer buf(*this);
Expand All @@ -1498,15 +1510,24 @@ void ConverterRefCount::ConvertUnionMemberAccessor(clang::MemberExpr *expr) {
str += "()";

if (isAddrOf()) {
StrCat(str);
if (member->getType()->isArrayType()) {
PushConversionKind push(*this, ConversionKind::Unboxed);
StrCat(std::format(
"{}.reinterpret_cast::<{}>()", str,
ToString(
member->getType()->getAsArrayTypeUnsafe()->getElementType())));
} else {
StrCat(str);
}
computed_expr_type_ = ComputedExprType::Pointer;
return;
}

if (isLValue()) {
pending_deref_.set(str);
return;
}
StrCat(DerefPtrExpr(str, expr->getMemberDecl()->getType()));
StrCat(DerefPtrExpr(str, member->getType()));
}

bool ConverterRefCount::VisitMemberExpr(clang::MemberExpr *expr) {
Expand Down
16 changes: 5 additions & 11 deletions libcc2rs/src/fn_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -146,20 +146,14 @@ impl<T> Eq for FnPtr<T> {}
impl<T: 'static> ByteRepr for FnPtr<T> {}

impl<T: 'static> ErasedPtr for FnPtr<T> {
fn pointee_type_id(&self) -> TypeId {
TypeId::of::<T>()
}
fn memcpy(&self, _src: &dyn ErasedPtr, _len: usize) {
panic!("memcpy not supported on fn pointer");
fn as_bytes(&self) -> Ptr<u8> {
panic!("byte view not supported on fn pointer");
}
fn as_any(&self) -> &dyn Any {
self
}
fn equals(&self, other: &dyn ErasedPtr) -> Option<bool> {
if self.pointee_type_id() != other.pointee_type_id() {
return None;
}
other.as_any().downcast_ref::<FnPtr<T>>().map(|o| self == o)
fn equals(&self, other: &dyn ErasedPtr) -> bool {
other.as_any().downcast_ref::<FnPtr<T>>() == Some(self)
}
fn is_null(&self) -> bool {
FnPtr::is_null(self)
Expand Down
90 changes: 18 additions & 72 deletions libcc2rs/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1042,49 +1042,33 @@ impl Ptr<u8> {
}

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<u8>;
fn as_any(&self) -> &dyn std::any::Any;
fn equals(&self, other: &dyn ErasedPtr) -> Option<bool>;
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<T> ErasedPtr for Ptr<T>
where
T: ByteRepr + 'static,
Ptr<T>: PartialEq,
{
fn pointee_type_id(&self) -> std::any::TypeId {
std::any::TypeId::of::<T>()
}

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::<Ptr<T>>()
.expect("memcpy: downcast to Ptr<T> failed");
let dst_bytes: Ptr<u8> = self.reinterpret_cast();
let src_bytes: Ptr<u8> = src_ptr.reinterpret_cast();
dst_bytes.memcpy(&src_bytes, len);
fn as_bytes(&self) -> Ptr<u8> {
self.reinterpret_cast::<u8>()
}

fn as_any(&self) -> &dyn std::any::Any {
self
}

fn equals(&self, other: &dyn ErasedPtr) -> Option<bool> {
if self.pointee_type_id() != other.pointee_type_id() {
return None;
}

if let Some(other_ptr) = other.as_any().downcast_ref::<Ptr<T>>() {
return Some(self == other_ptr);
}

None
fn equals(&self, other: &dyn ErasedPtr) -> bool {
other.as_any().downcast_ref::<Ptr<T>>() == Some(self)
}

fn is_null(&self) -> bool {
Expand Down Expand Up @@ -1118,66 +1102,28 @@ impl AnyPtr {
}
self.ptr.as_any().downcast_ref::<Ptr<T>>().cloned()
}

pub fn reinterpret_cast<T: ByteRepr>(&self) -> Ptr<T> {
macro_rules! try_src {
($ty:ty) => {{
if let Some(p) = self.cast::<$ty>() {
return p.reinterpret_cast::<T>();
}
if let Some(pv) = self.cast::<Vec<$ty>>() {
return pv.reinterpret_cast::<T>();
}
}};
}

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<u8> = self.reinterpret_cast();
let src_u8: Ptr<u8> = 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<u8> = 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<u8> = self.reinterpret_cast();
let b: Ptr<u8> = other.reinterpret_cast();
let a = self.ptr.as_bytes();
let b = other.ptr.as_bytes();
a.memcmp(&b, len)
}
}
Expand Down
23 changes: 23 additions & 0 deletions tests/unit/memcpy_struct_bytes.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <assert.h>
#include <stdint.h>
#include <string.h>

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;
}
58 changes: 58 additions & 0 deletions tests/unit/out/refcount/memcpy_struct_bytes.rs
Original file line number Diff line number Diff line change
@@ -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<i32>,
pub y: Value<i32>,
}
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(<i32>::from_bytes(&buf[0..4]))),
y: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
}
}
}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let src: Value<point> = Rc::new(RefCell::new(point {
x: Rc::new(RefCell::new(3)),
y: Rc::new(RefCell::new(7)),
}));
let buf: Value<Box<[u8]>> = Rc::new(RefCell::new(
(0..8).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
));
{
((buf.as_pointer() as Ptr<u8>) as Ptr<u8>).to_any().memcpy(
&((src.as_pointer()) as Ptr<point>).to_any(),
::std::mem::size_of::<[u8; 8]>() as usize,
);
((buf.as_pointer() as Ptr<u8>) as Ptr<u8>).to_any().clone()
};
let dst: Value<point> = <Value<point>>::default();
{
((dst.as_pointer()) as Ptr<point>).to_any().memcpy(
&((buf.as_pointer() as Ptr<u8>) as Ptr<u8>).to_any(),
8usize as usize,
);
((dst.as_pointer()) as Ptr<point>).to_any().clone()
};
assert!(((((*(*dst.borrow()).x.borrow()) == 3) as i32) != 0));
assert!(((((*(*dst.borrow()).y.borrow()) == 7) as i32) != 0));
return 0;
}
Loading
Loading