diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 65929016..d2cce119 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -58,9 +58,8 @@ use std::rc::Rc; std::string Converter::EmitOpaqueRecords() { std::string out; record_decls_.ForEachUndefined([&](const std::string &name) { - out += "pub struct "; - out += name; - out += ";\n"; + out += std::format("pub struct {};\n", name); + out += std::format("impl ByteRepr for {} {{}}\n", name); }); return out; } diff --git a/libcc2rs/src/fn_ptr.rs b/libcc2rs/src/fn_ptr.rs index e7152279..311e3e38 100644 --- a/libcc2rs/src/fn_ptr.rs +++ b/libcc2rs/src/fn_ptr.rs @@ -158,6 +158,9 @@ impl ErasedPtr for FnPtr { fn is_null(&self) -> bool { FnPtr::is_null(self) } + fn is_dangling(&self) -> bool { + false + } } impl FnPtr { diff --git a/libcc2rs/src/rc.rs b/libcc2rs/src/rc.rs index f13be101..cd5f97f9 100644 --- a/libcc2rs/src/rc.rs +++ b/libcc2rs/src/rc.rs @@ -3,7 +3,7 @@ use crate::{PostfixDec, PostfixInc, PrefixDec, PrefixInc}; use std::any::{Any, TypeId}; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::{ cell::{Ref, RefCell, RefMut}, @@ -402,13 +402,17 @@ impl Ptr { return self_any.downcast_ref::>().unwrap().clone(); } + if self.is_null() { + return Ptr::null(); + } + if U::byte_size() == 0 { panic!("cannot reinterpret_cast to zero-sized type"); } let src_byte_off = self.offset.wrapping_mul(T::byte_size()); let (alloc, abs_byte_off): (Rc, usize) = match &self.kind { - PtrKind::Null => return Ptr::null(), + PtrKind::Null => unreachable!(), PtrKind::StackSingle(weak) | PtrKind::HeapSingle(weak) => ( Rc::new(SingleOriginalAlloc { weak: weak.clone() }), src_byte_off, @@ -434,6 +438,24 @@ impl Ptr { } } +impl Ptr { + #[inline] + fn c_byte_len(&self) -> usize { + match &self.kind { + PtrKind::Reinterpreted(data) => data.alloc.total_byte_len(), + _ => self.len().wrapping_mul(T::byte_size()), + } + } + + #[inline] + fn c_byte_offset(&self) -> usize { + match &self.kind { + PtrKind::Reinterpreted(_) => self.offset, + _ => self.offset.wrapping_mul(T::byte_size()), + } + } +} + impl Ptr { pub fn with_mut(&self, f: impl FnOnce(&mut T) -> R) -> R where @@ -1050,6 +1072,7 @@ pub(crate) trait ErasedPtr: std::any::Any { fn as_any(&self) -> &dyn std::any::Any; fn equals(&self, other: &dyn ErasedPtr) -> bool; fn is_null(&self) -> bool; + fn is_dangling(&self) -> bool; } impl PartialEq for dyn ErasedPtr { @@ -1072,12 +1095,25 @@ where } fn equals(&self, other: &dyn ErasedPtr) -> bool { - other.as_any().downcast_ref::>() == Some(self) + if let Some(o) = other.as_any().downcast_ref::>() { + return o == self; + } + self.as_bytes() == other.as_bytes() } fn is_null(&self) -> bool { Ptr::is_null(self) } + + fn is_dangling(&self) -> bool { + match &self.kind { + PtrKind::Null => false, + PtrKind::StackSingle(w) | PtrKind::HeapSingle(w) => w.strong_count() == 0, + PtrKind::Vec(w) => w.strong_count() == 0, + PtrKind::StackArray(w) | PtrKind::HeapArray(w) => w.strong_count() == 0, + PtrKind::Reinterpreted(data) => data.alloc.is_dangling(), + } + } } #[derive(Clone)] @@ -1208,8 +1244,140 @@ impl AsPointerDyn for Rc> { } } -impl ByteRepr for Ptr {} -impl ByteRepr for AnyPtr {} +type RealAddr = usize; +type SyntheticAddr = usize; +type ByteLen = usize; + +struct RangeAllocator { + cursor: SyntheticAddr, + bases: HashMap, +} + +impl RangeAllocator { + fn new() -> Self { + Self { + // Increase this if you need higher alignment. In general, malloc returns + // 16-bits-aligned pointers, but that's not relevant for now. + cursor: 1, + bases: HashMap::new(), + } + } + + fn get_synthetic_addr(&mut self, real_addr: RealAddr, byte_len: ByteLen) -> SyntheticAddr { + if let Some(&(base, capacity)) = self.bases.get(&real_addr) + && byte_len <= capacity + { + return base; + } + let base = self.cursor; + self.cursor = base + byte_len + 1; + self.bases.insert(real_addr, (base, byte_len)); + base + } +} + +struct PtrRegistry { + ranges: RangeAllocator, + entries: BTreeMap, + evicted_len: usize, +} + +impl PtrRegistry { + fn new() -> Self { + Self { + ranges: RangeAllocator::new(), + entries: BTreeMap::new(), + evicted_len: 0, + } + } + + fn put(&mut self, real_addr: RealAddr, byte_len: ByteLen, ptr: AnyPtr) -> SyntheticAddr { + self.evict_dead(); + let base = self.ranges.get_synthetic_addr(real_addr, byte_len); + self.entries.insert(base, (ptr, byte_len)); + base + } + + fn get(&self, addr: SyntheticAddr) -> Option<(SyntheticAddr, AnyPtr, ByteLen)> { + self.entries + .range(..=addr) + .next_back() + .map(|(base, (any, len))| (*base, any.clone(), *len)) + } + + fn evict_dead(&mut self) { + if self.entries.len() < 16.max(2 * self.evicted_len) { + return; + } + self.entries.retain(|_, (any, _)| !any.ptr.is_dangling()); + let entries = &self.entries; + self.ranges + .bases + .retain(|_, &mut (base, _)| entries.contains_key(&base)); + self.evicted_len = self.entries.len(); + } +} + +thread_local! { + static PTR_REGISTRY: RefCell = RefCell::new(PtrRegistry::new()); +} + +impl ByteRepr for Ptr { + fn byte_size() -> usize { + std::mem::size_of::() + } + + fn to_bytes(&self, buf: &mut [u8]) { + if self.is_null() { + 0usize.to_bytes(buf); + return; + } + let base = PTR_REGISTRY.with(|r| { + r.borrow_mut().put( + self.kind.address(), + self.c_byte_len(), + Ptr { + offset: 0, + kind: self.kind.clone(), + } + .to_any(), + ) + }); + base.wrapping_add(self.c_byte_offset()).to_bytes(buf); + } + + fn from_bytes(buf: &[u8]) -> Self { + let addr = usize::from_bytes(buf); + if addr == 0 { + return Ptr::null(); + } + let entry = PTR_REGISTRY.with(|r| r.borrow().get(addr)); + let Some((base, any, byte_len)) = entry else { + panic!("ub: cast of invalid address 0x{addr:x} to pointer"); + }; + let delta = addr - base; + if delta > byte_len { + panic!("ub: cast of invalid address 0x{addr:x} to pointer"); + } + let elem_size = T::byte_size(); + assert_eq!(delta % elem_size, 0, "ub: misaligned pointer"); + any.reinterpret_cast::().offset(delta / elem_size) + } +} + +impl ByteRepr for AnyPtr { + fn byte_size() -> usize { + std::mem::size_of::() + } + + fn to_bytes(&self, buf: &mut [u8]) { + self.ptr.as_bytes().to_bytes(buf); + } + + fn from_bytes(buf: &[u8]) -> Self { + Ptr::::from_bytes(buf).to_any() + } +} #[cfg(test)] mod tests { diff --git a/libcc2rs/src/reinterpret.rs b/libcc2rs/src/reinterpret.rs index b496f8b2..d9f814e6 100644 --- a/libcc2rs/src/reinterpret.rs +++ b/libcc2rs/src/reinterpret.rs @@ -100,6 +100,7 @@ pub trait OriginalAlloc { fn total_byte_len(&self) -> usize; // Stable address used for pointer equality across PtrKind variants. fn address(&self) -> usize; + fn is_dangling(&self) -> bool; } // Read bytes starting at `byte_offset` from a slice of S elements into `buf`. @@ -165,6 +166,10 @@ impl OriginalAlloc for SingleOriginalAlloc { fn address(&self) -> usize { self.weak.as_ptr() as usize } + + fn is_dangling(&self) -> bool { + self.weak.strong_count() == 0 + } } pub(crate) trait AsSlice { @@ -219,4 +224,8 @@ impl OriginalAlloc for SliceOriginalAlloc { fn address(&self) -> usize { self.weak.as_ptr() as usize } + + fn is_dangling(&self) -> bool { + self.weak.strong_count() == 0 + } } diff --git a/tests/multi-file/opaque_forward_decl/out/refcount/opaque_forward_decl.rs b/tests/multi-file/opaque_forward_decl/out/refcount/opaque_forward_decl.rs index 77d2b14b..0fbcf008 100644 --- a/tests/multi-file/opaque_forward_decl/out/refcount/opaque_forward_decl.rs +++ b/tests/multi-file/opaque_forward_decl/out/refcount/opaque_forward_decl.rs @@ -44,3 +44,4 @@ pub fn touch_0(c: Ptr) { (*(*(*c.borrow()).upgrade().deref()).p.borrow()).clone(); } pub struct opaque; +impl ByteRepr for opaque {} diff --git a/tests/multi-file/opaque_forward_decl/out/unsafe/opaque_forward_decl.rs b/tests/multi-file/opaque_forward_decl/out/unsafe/opaque_forward_decl.rs index 798b5256..aa1feb94 100644 --- a/tests/multi-file/opaque_forward_decl/out/unsafe/opaque_forward_decl.rs +++ b/tests/multi-file/opaque_forward_decl/out/unsafe/opaque_forward_decl.rs @@ -31,3 +31,4 @@ pub unsafe fn touch_0(mut c: *mut container) { &((*c).p); } pub struct opaque; +impl ByteRepr for opaque {} diff --git a/tests/ub/int_to_pointer_out_of_range.c b/tests/ub/int_to_pointer_out_of_range.c new file mode 100644 index 00000000..361f1a66 --- /dev/null +++ b/tests/ub/int_to_pointer_out_of_range.c @@ -0,0 +1,19 @@ +// panic-ub: refcount +// nondet-result: unsafe + +#include + +int main(void) { + int arr[4] = {1, 2, 3, 4}; + + union { + int *p; + uintptr_t bits; + } u; + + u.p = arr; + u.bits += 100 * sizeof(int); + int *p = u.p; + + return *p == 0 ? 0 : 1; +} diff --git a/tests/ub/int_to_pointer_random.c b/tests/ub/int_to_pointer_random.c new file mode 100644 index 00000000..9c345ef9 --- /dev/null +++ b/tests/ub/int_to_pointer_random.c @@ -0,0 +1,16 @@ +// panic-ub: refcount +// nondet-result: unsafe + +#include + +int main(void) { + union { + int *p; + uintptr_t bits; + } u; + + u.bits = 0xdeadbeef; + int *p = u.p; + + return *p == 0 ? 0 : 1; +} diff --git a/tests/ub/out/refcount/int_to_pointer_out_of_range.rs b/tests/ub/out/refcount/int_to_pointer_out_of_range.rs new file mode 100644 index 00000000..515c32e0 --- /dev/null +++ b/tests/ub/out/refcount/int_to_pointer_out_of_range.rs @@ -0,0 +1,64 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let arr: Value> = Rc::new(RefCell::new(Box::new([1, 2, 3, 4]))); + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn p(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn bits(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + } + impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } + }; + let u: Value = >::default(); + (*u.borrow_mut()).p().write((arr.as_pointer() as Ptr)); + let rhs_0 = ((((*u.borrow()).bits().read()) as u64) + .wrapping_add(((100_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + (*u.borrow_mut()).bits().write(rhs_0); + let p: Value> = Rc::new(RefCell::new(((*u.borrow()).p().read()).clone())); + return if (((((*p.borrow()).read()) == 0) as i32) != 0) { + 0 + } else { + 1 + }; +} diff --git a/tests/ub/out/refcount/int_to_pointer_random.rs b/tests/ub/out/refcount/int_to_pointer_random.rs new file mode 100644 index 00000000..9ae7e358 --- /dev/null +++ b/tests/ub/out/refcount/int_to_pointer_random.rs @@ -0,0 +1,59 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn p(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn bits(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + } + impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } + }; + let u: Value = >::default(); + (*u.borrow_mut()).bits().write(3735928559_u64); + let p: Value> = Rc::new(RefCell::new(((*u.borrow()).p().read()).clone())); + return if (((((*p.borrow()).read()) == 0) as i32) != 0) { + 0 + } else { + 1 + }; +} diff --git a/tests/ub/out/unsafe/int_to_pointer_out_of_range.rs b/tests/ub/out/unsafe/int_to_pointer_out_of_range.rs new file mode 100644 index 00000000..2ca6e907 --- /dev/null +++ b/tests/ub/out/unsafe/int_to_pointer_out_of_range.rs @@ -0,0 +1,34 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [i32; 4] = [1, 2, 3, 4]; + #[repr(C)] + #[derive(Copy, Clone)] + pub union anon_0 { + pub p: *mut i32, + pub bits: u64, + } + impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } + }; + let mut u: anon_0 = ::default(); + u.p = arr.as_mut_ptr(); + u.bits = ((u.bits as u64) + .wrapping_add(((100_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + let mut p: *mut i32 = u.p; + return if ((((*p) == (0)) as i32) != 0) { 0 } else { 1 }; +} diff --git a/tests/ub/out/unsafe/int_to_pointer_random.rs b/tests/ub/out/unsafe/int_to_pointer_random.rs new file mode 100644 index 00000000..56f52df5 --- /dev/null +++ b/tests/ub/out/unsafe/int_to_pointer_random.rs @@ -0,0 +1,30 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + #[repr(C)] + #[derive(Copy, Clone)] + pub union anon_0 { + pub p: *mut i32, + pub bits: u64, + } + impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } + }; + let mut u: anon_0 = ::default(); + u.bits = 3735928559_u64; + let mut p: *mut i32 = u.p; + return if ((((*p) == (0)) as i32) != 0) { 0 } else { 1 }; +} diff --git a/tests/unit/out/refcount/opaque_forward_decl.rs b/tests/unit/out/refcount/opaque_forward_decl.rs index 0403bbae..ec354de3 100644 --- a/tests/unit/out/refcount/opaque_forward_decl.rs +++ b/tests/unit/out/refcount/opaque_forward_decl.rs @@ -38,3 +38,4 @@ fn main_0() -> i32 { return ((*(*c.borrow()).x.borrow()) - 42); } pub struct opaque; +impl ByteRepr for opaque {} diff --git a/tests/unit/out/refcount/struct_member_array_adjacency.rs b/tests/unit/out/refcount/struct_member_array_adjacency.rs new file mode 100644 index 00000000..cbb8d467 --- /dev/null +++ b/tests/unit/out/refcount/struct_member_array_adjacency.rs @@ -0,0 +1,52 @@ +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()] +pub struct pair { + pub a: Value>, + pub b: Value>, +} +impl Default for pair { + fn default() -> Self { + pair { + a: Rc::new(RefCell::new( + (0..4).map(|_| ::default()).collect::>(), + )), + b: Rc::new(RefCell::new( + (0..4).map(|_| ::default()).collect::>(), + )), + } + } +} +impl ByteRepr for pair { + fn byte_size() -> usize { + 32 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..16]); + (*self.b.borrow()).to_bytes(&mut buf[16..32]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(>::from_bytes(&buf[0..16]))), + b: Rc::new(RefCell::new(>::from_bytes(&buf[16..32]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let s: Value = >::default(); + assert!( + (((((*s.borrow()).a.as_pointer() as Ptr::).offset((4) as isize) + == ((*s.borrow()).b.as_pointer() as Ptr::)) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_pointer_int_roundtrip.rs b/tests/unit/out/refcount/union_pointer_int_roundtrip.rs new file mode 100644 index 00000000..6e2bd896 --- /dev/null +++ b/tests/unit/out/refcount/union_pointer_int_roundtrip.rs @@ -0,0 +1,92 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let arr: Value> = Rc::new(RefCell::new(Box::new([10, 20, 30, 40]))); + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn p(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn bits(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + } + impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } + }; + let u: Value = >::default(); + (*u.borrow_mut()) + .p() + .write(((arr.as_pointer() as Ptr).offset(1))); + let rhs_0 = ((((*u.borrow()).bits().read()) as u64) + .wrapping_add(((2_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + (*u.borrow_mut()).bits().write(rhs_0); + let q: Value> = Rc::new(RefCell::new(((*u.borrow()).p().read()).clone())); + assert!((((((*q.borrow()).read()) == 40) as i32) != 0)); + assert!( + ((({ + let _lhs = (*q.borrow()).clone(); + _lhs == ((arr.as_pointer() as Ptr).offset(3)) + }) as i32) + != 0) + ); + let rhs_0 = ((((*u.borrow()).bits().read()) as u64) + .wrapping_sub(((3_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + (*u.borrow_mut()).bits().write(rhs_0); + assert!( + ((({ + let _lhs = ((*u.borrow()).p().read()).clone(); + _lhs == ((arr.as_pointer() as Ptr).offset(0)) + }) as i32) + != 0) + ); + assert!(((((((*u.borrow()).p().read()).read()) == 10) as i32) != 0)); + (*u.borrow_mut()) + .p() + .write((arr.as_pointer() as Ptr).offset((4) as isize)); + assert!( + ((({ + let _lhs = ((*u.borrow()).p().read()).clone(); + _lhs == (arr.as_pointer() as Ptr).offset((4) as isize) + }) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/refcount/union_pointer_null_roundtrip.rs b/tests/unit/out/refcount/union_pointer_null_roundtrip.rs new file mode 100644 index 00000000..20f8bdf0 --- /dev/null +++ b/tests/unit/out/refcount/union_pointer_null_roundtrip.rs @@ -0,0 +1,62 @@ +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}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn p(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn bits(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + } + impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } + }; + let u: Value = >::default(); + (*u.borrow_mut()).bits().write(0_u64); + assert!((((((*u.borrow()).p().read()).is_null()) as i32) != 0)); + let x: Value = Rc::new(RefCell::new(5)); + (*u.borrow_mut()).p().write((x.as_pointer())); + assert!((((((*u.borrow()).bits().read()) != 0_u64) as i32) != 0)); + (*u.borrow_mut()).bits().write(0_u64); + assert!((((((*u.borrow()).p().read()).is_null()) as i32) != 0)); + (*u.borrow_mut()).p().write(Ptr::::null()); + assert!((((((*u.borrow()).bits().read()) == 0_u64) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/refcount/union_struct_pointer_roundtrip.rs b/tests/unit/out/refcount/union_struct_pointer_roundtrip.rs new file mode 100644 index 00000000..6374de14 --- /dev/null +++ b/tests/unit/out/refcount/union_struct_pointer_roundtrip.rs @@ -0,0 +1,112 @@ +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 pair { + pub x: Value, + pub y: Value, +} +impl ByteRepr for pair { + 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 arr: Value> = Rc::new(RefCell::new( + (0..3).map(|_| ::default()).collect::>(), + )); + (*(*arr.borrow())[(0) as usize].x.borrow_mut()) = 10; + (*(*arr.borrow())[(1) as usize].x.borrow_mut()) = 20; + (*(*arr.borrow())[(2) as usize].x.borrow_mut()) = 30; + pub struct anon_0 { + __bytes: Value>, + } + impl anon_0 { + pub fn p(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn bits(&self) -> Ptr { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + } + impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } + } + impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } + } + impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } + }; + let u: Value = >::default(); + (*u.borrow_mut()) + .p() + .write(((arr.as_pointer() as Ptr).offset(1))); + let q: Value> = Rc::new(RefCell::new(((*u.borrow()).p().read()).clone())); + assert!(((((*(*(*q.borrow()).upgrade().deref()).x.borrow()) == 20) as i32) != 0)); + assert!( + ((({ + let _lhs = (*q.borrow()).clone(); + _lhs == ((arr.as_pointer() as Ptr).offset(1)) + }) as i32) + != 0) + ); + let rhs_0 = ((((*u.borrow()).bits().read()) as u64).wrapping_add((8usize as u64))) as u64; + (*u.borrow_mut()).bits().write(rhs_0); + assert!(((((*(*((*u.borrow()).p().read()).upgrade().deref()).x.borrow()) == 30) as i32) != 0)); + assert!( + ((({ + let _lhs = ((*u.borrow()).p().read()).clone(); + _lhs == ((arr.as_pointer() as Ptr).offset(2)) + }) as i32) + != 0) + ); + let rhs_0 = ((((*u.borrow()).bits().read()) as u64) + .wrapping_sub(((2_usize).wrapping_mul((8usize as usize)) as u64))) as u64; + (*u.borrow_mut()).bits().write(rhs_0); + assert!(((((*(*((*u.borrow()).p().read()).upgrade().deref()).x.borrow()) == 10) as i32) != 0)); + assert!( + ((({ + let _lhs = ((*u.borrow()).p().read()).clone(); + _lhs == ((arr.as_pointer() as Ptr).offset(0)) + }) as i32) + != 0) + ); + return 0; +} diff --git a/tests/unit/out/unsafe/opaque_forward_decl.rs b/tests/unit/out/unsafe/opaque_forward_decl.rs index 966d4ee6..96bd6296 100644 --- a/tests/unit/out/unsafe/opaque_forward_decl.rs +++ b/tests/unit/out/unsafe/opaque_forward_decl.rs @@ -26,3 +26,4 @@ unsafe fn main_0() -> i32 { return ((c.x) - (42)); } pub struct opaque; +impl ByteRepr for opaque {} diff --git a/tests/unit/out/unsafe/struct_member_array_adjacency.rs b/tests/unit/out/unsafe/struct_member_array_adjacency.rs new file mode 100644 index 00000000..c5a8a747 --- /dev/null +++ b/tests/unit/out/unsafe/struct_member_array_adjacency.rs @@ -0,0 +1,32 @@ +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)] +pub struct pair { + pub a: [i32; 4], + pub b: [i32; 4], +} +impl Default for pair { + fn default() -> Self { + pair { + a: [0_i32; 4], + b: [0_i32; 4], + } + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: pair = ::default(); + assert!(((((s.a.as_mut_ptr().offset((4) as isize)) == (s.b.as_mut_ptr())) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/union_pointer_int_roundtrip.rs b/tests/unit/out/unsafe/union_pointer_int_roundtrip.rs new file mode 100644 index 00000000..01c03227 --- /dev/null +++ b/tests/unit/out/unsafe/union_pointer_int_roundtrip.rs @@ -0,0 +1,43 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [i32; 4] = [10, 20, 30, 40]; + #[repr(C)] + #[derive(Copy, Clone)] + pub union anon_0 { + pub p: *mut i32, + pub bits: u64, + } + impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } + }; + let mut u: anon_0 = ::default(); + u.p = (&mut arr[(1) as usize] as *mut i32); + u.bits = ((u.bits as u64) + .wrapping_add(((2_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + let mut q: *mut i32 = u.p; + assert!(((((*q) == (40)) as i32) != 0)); + assert!(((((q) == (&mut arr[(3) as usize] as *mut i32)) as i32) != 0)); + u.bits = ((u.bits as u64) + .wrapping_sub(((3_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + assert!(((((u.p) == (&mut arr[(0) as usize] as *mut i32)) as i32) != 0)); + assert!(((((*u.p) == (10)) as i32) != 0)); + u.p = arr.as_mut_ptr().offset((4) as isize); + assert!(((((u.p) == (arr.as_mut_ptr().offset((4) as isize))) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/union_pointer_null_roundtrip.rs b/tests/unit/out/unsafe/union_pointer_null_roundtrip.rs new file mode 100644 index 00000000..4f9c1ea1 --- /dev/null +++ b/tests/unit/out/unsafe/union_pointer_null_roundtrip.rs @@ -0,0 +1,37 @@ +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; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + #[repr(C)] + #[derive(Copy, Clone)] + pub union anon_0 { + pub p: *mut i32, + pub bits: u64, + } + impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } + }; + let mut u: anon_0 = ::default(); + u.bits = 0_u64; + assert!(((((u.p).is_null()) as i32) != 0)); + let mut x: i32 = 5; + u.p = (&mut x as *mut i32); + assert!(((((u.bits) != (0_u64)) as i32) != 0)); + u.bits = 0_u64; + assert!(((((u.p).is_null()) as i32) != 0)); + u.p = std::ptr::null_mut(); + assert!(((((u.bits) == (0_u64)) as i32) != 0)); + return 0; +} diff --git a/tests/unit/out/unsafe/union_struct_pointer_roundtrip.rs b/tests/unit/out/unsafe/union_struct_pointer_roundtrip.rs new file mode 100644 index 00000000..c384ca9e --- /dev/null +++ b/tests/unit/out/unsafe/union_struct_pointer_roundtrip.rs @@ -0,0 +1,50 @@ +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 pair { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [pair; 3] = [::default(); 3]; + arr[(0) as usize].x = 10; + arr[(1) as usize].x = 20; + arr[(2) as usize].x = 30; + #[repr(C)] + #[derive(Copy, Clone)] + pub union anon_0 { + pub p: *mut pair, + pub bits: u64, + } + impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } + }; + let mut u: anon_0 = ::default(); + u.p = (&mut arr[(1) as usize] as *mut pair); + let mut q: *mut pair = u.p; + assert!((((((*q).x) == (20)) as i32) != 0)); + assert!(((((q) == (&mut arr[(1) as usize] as *mut pair)) as i32) != 0)); + u.bits = ((u.bits as u64).wrapping_add((::std::mem::size_of::() as u64))) as u64; + assert!((((((*u.p).x) == (30)) as i32) != 0)); + assert!(((((u.p) == (&mut arr[(2) as usize] as *mut pair)) as i32) != 0)); + u.bits = ((u.bits as u64) + .wrapping_sub(((2_usize).wrapping_mul((::std::mem::size_of::() as usize)) as u64))) + as u64; + assert!((((((*u.p).x) == (10)) as i32) != 0)); + assert!(((((u.p) == (&mut arr[(0) as usize] as *mut pair)) as i32) != 0)); + return 0; +} diff --git a/tests/unit/struct_member_array_adjacency.c b/tests/unit/struct_member_array_adjacency.c new file mode 100644 index 00000000..4206f0e8 --- /dev/null +++ b/tests/unit/struct_member_array_adjacency.c @@ -0,0 +1,14 @@ +// panic: refcount +#include + +struct pair { + int a[4]; + int b[4]; +}; + +int main(void) { + struct pair s; + + assert(s.a + 4 == s.b); + return 0; +} diff --git a/tests/unit/union_pointer_int_roundtrip.c b/tests/unit/union_pointer_int_roundtrip.c new file mode 100644 index 00000000..ef9f3cff --- /dev/null +++ b/tests/unit/union_pointer_int_roundtrip.c @@ -0,0 +1,27 @@ +#include +#include + +int main(void) { + int arr[4] = {10, 20, 30, 40}; + + union { + int *p; + uintptr_t bits; + } u; + + u.p = &arr[1]; + u.bits += 2 * sizeof(int); + int *q = u.p; + + assert(*q == 40); + assert(q == &arr[3]); + + u.bits -= 3 * sizeof(int); + assert(u.p == &arr[0]); + assert(*u.p == 10); + + u.p = arr + 4; + assert(u.p == arr + 4); + + return 0; +} diff --git a/tests/unit/union_pointer_null_roundtrip.c b/tests/unit/union_pointer_null_roundtrip.c new file mode 100644 index 00000000..2114ecc7 --- /dev/null +++ b/tests/unit/union_pointer_null_roundtrip.c @@ -0,0 +1,25 @@ +#include +#include +#include + +int main(void) { + union { + int *p; + uintptr_t bits; + } u; + + u.bits = 0; + assert(u.p == NULL); + + int x = 5; + u.p = &x; + assert(u.bits != 0); + + u.bits = 0; + assert(u.p == NULL); + + u.p = NULL; + assert(u.bits == 0); + + return 0; +} diff --git a/tests/unit/union_pointer_pun_address.c b/tests/unit/union_pointer_pun_address.c index 75123e0c..163841d6 100644 --- a/tests/unit/union_pointer_pun_address.c +++ b/tests/unit/union_pointer_pun_address.c @@ -1,4 +1,3 @@ -// panic: refcount #include struct node_a { diff --git a/tests/unit/union_pointer_pun_writethrough.c b/tests/unit/union_pointer_pun_writethrough.c index 44bd842f..b03d57a0 100644 --- a/tests/unit/union_pointer_pun_writethrough.c +++ b/tests/unit/union_pointer_pun_writethrough.c @@ -1,4 +1,3 @@ -// panic: refcount #include int main(void) { diff --git a/tests/unit/union_struct_pointer_roundtrip.c b/tests/unit/union_struct_pointer_roundtrip.c new file mode 100644 index 00000000..d43f4ba8 --- /dev/null +++ b/tests/unit/union_struct_pointer_roundtrip.c @@ -0,0 +1,34 @@ +#include +#include + +struct pair { + int x; + int y; +}; + +int main(void) { + struct pair arr[3]; + arr[0].x = 10; + arr[1].x = 20; + arr[2].x = 30; + + union { + struct pair *p; + uintptr_t bits; + } u; + + u.p = &arr[1]; + struct pair *q = u.p; + assert(q->x == 20); + assert(q == &arr[1]); + + u.bits += sizeof(struct pair); + assert(u.p->x == 30); + assert(u.p == &arr[2]); + + u.bits -= 2 * sizeof(struct pair); + assert(u.p->x == 10); + assert(u.p == &arr[0]); + + return 0; +} diff --git a/tests/unit/union_tagged_many_arms.c b/tests/unit/union_tagged_many_arms.c index 7e83b42a..e3677004 100644 --- a/tests/unit/union_tagged_many_arms.c +++ b/tests/unit/union_tagged_many_arms.c @@ -1,4 +1,3 @@ -// panic: refcount #include #include diff --git a/tests/unit/union_tagged_simple.c b/tests/unit/union_tagged_simple.c index 3bc7daa1..6efa44de 100644 --- a/tests/unit/union_tagged_simple.c +++ b/tests/unit/union_tagged_simple.c @@ -1,4 +1,3 @@ -// panic: refcount #include typedef enum { diff --git a/tests/unit/union_void_ptr_sized_deref.c b/tests/unit/union_void_ptr_sized_deref.c index 26306517..586a608e 100644 --- a/tests/unit/union_void_ptr_sized_deref.c +++ b/tests/unit/union_void_ptr_sized_deref.c @@ -1,4 +1,3 @@ -// panic: refcount #include #include #include