Skip to content

Commit 7e10a1d

Browse files
committed
Add ByteRepr for Ptr and AnyPtr
1 parent e75e87d commit 7e10a1d

1 file changed

Lines changed: 105 additions & 3 deletions

File tree

libcc2rs/src/rc.rs

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use crate::{PostfixDec, PostfixInc, PrefixDec, PrefixInc};
55
use std::any::{Any, TypeId};
6-
use std::collections::HashMap;
6+
use std::collections::{BTreeMap, HashMap};
77

88
use std::{
99
cell::{Ref, RefCell, RefMut},
@@ -1208,8 +1208,110 @@ impl<T: ?Sized> AsPointerDyn<T> for Rc<RefCell<T>> {
12081208
}
12091209
}
12101210

1211-
impl<T: 'static> ByteRepr for Ptr<T> {}
1212-
impl ByteRepr for AnyPtr {}
1211+
type RealAddr = usize;
1212+
type SyntheticAddr = usize;
1213+
type ByteLen = usize;
1214+
1215+
struct RangeAllocator {
1216+
cursor: SyntheticAddr,
1217+
bases: HashMap<RealAddr, (SyntheticAddr, ByteLen)>,
1218+
}
1219+
1220+
impl RangeAllocator {
1221+
fn new() -> Self {
1222+
Self {
1223+
// Increase this if you need higher alignment. In general, malloc returns
1224+
// 16-bits-aligned pointers, but that's not relevant for now.
1225+
cursor: 1,
1226+
bases: HashMap::new(),
1227+
}
1228+
}
1229+
1230+
fn base_for(&mut self, real_addr: RealAddr, byte_len: ByteLen) -> SyntheticAddr {
1231+
if let Some(&(base, capacity)) = self.bases.get(&real_addr) {
1232+
if byte_len <= capacity {
1233+
return base;
1234+
}
1235+
}
1236+
let base = self.cursor;
1237+
self.cursor = base + byte_len + 1;
1238+
self.bases.insert(real_addr, (base, byte_len));
1239+
base
1240+
}
1241+
}
1242+
1243+
thread_local! {
1244+
static PTR_RANGE_ALLOC: RefCell<RangeAllocator> = RefCell::new(RangeAllocator::new());
1245+
static PTR_REGISTRY: RefCell<BTreeMap<SyntheticAddr, (AnyPtr, ByteLen)>> =
1246+
const { RefCell::new(BTreeMap::new()) };
1247+
}
1248+
1249+
impl<T: ByteRepr> ByteRepr for Ptr<T> {
1250+
fn byte_size() -> usize {
1251+
std::mem::size_of::<usize>()
1252+
}
1253+
1254+
fn to_bytes(&self, buf: &mut [u8]) {
1255+
if self.is_null() {
1256+
0usize.to_bytes(buf);
1257+
return;
1258+
}
1259+
let (byte_off, byte_len) = match &self.kind {
1260+
PtrKind::Reinterpreted(data) => (self.offset, data.alloc.total_byte_len()),
1261+
_ => (
1262+
self.offset.wrapping_mul(T::byte_size()),
1263+
self.len() * T::byte_size(),
1264+
),
1265+
};
1266+
let base =
1267+
PTR_RANGE_ALLOC.with(|a| a.borrow_mut().base_for(self.kind.address(), byte_len));
1268+
let rebased = Ptr {
1269+
offset: 0,
1270+
kind: self.kind.clone(),
1271+
};
1272+
PTR_REGISTRY.with(|r| {
1273+
r.borrow_mut().insert(base, (rebased.to_any(), byte_len));
1274+
});
1275+
base.wrapping_add(byte_off).to_bytes(buf);
1276+
}
1277+
1278+
fn from_bytes(buf: &[u8]) -> Self {
1279+
let addr = usize::from_bytes(buf);
1280+
if addr == 0 {
1281+
return Ptr::null();
1282+
}
1283+
let entry = PTR_REGISTRY.with(|r| {
1284+
r.borrow()
1285+
.range(..=addr)
1286+
.next_back()
1287+
.map(|(base, (any, len))| (*base, any.clone(), *len))
1288+
});
1289+
let Some((base, any, byte_len)) = entry else {
1290+
panic!("ub: cast of invalid address 0x{addr:x} to pointer");
1291+
};
1292+
let delta = addr - base;
1293+
if delta > byte_len {
1294+
panic!("ub: cast of invalid address 0x{addr:x} to pointer");
1295+
}
1296+
let elem_size = T::byte_size();
1297+
assert_eq!(delta % elem_size, 0, "ub: misaligned pointer");
1298+
any.reinterpret_cast::<T>().offset(delta / elem_size)
1299+
}
1300+
}
1301+
1302+
impl ByteRepr for AnyPtr {
1303+
fn byte_size() -> usize {
1304+
std::mem::size_of::<usize>()
1305+
}
1306+
1307+
fn to_bytes(&self, buf: &mut [u8]) {
1308+
self.ptr.as_bytes().to_bytes(buf);
1309+
}
1310+
1311+
fn from_bytes(buf: &[u8]) -> Self {
1312+
Ptr::<u8>::from_bytes(buf).to_any()
1313+
}
1314+
}
12131315

12141316
#[cfg(test)]
12151317
mod tests {

0 commit comments

Comments
 (0)