|
3 | 3 |
|
4 | 4 | use crate::{PostfixDec, PostfixInc, PrefixDec, PrefixInc}; |
5 | 5 | use std::any::{Any, TypeId}; |
6 | | -use std::collections::HashMap; |
| 6 | +use std::collections::{BTreeMap, HashMap}; |
7 | 7 |
|
8 | 8 | use std::{ |
9 | 9 | cell::{Ref, RefCell, RefMut}, |
@@ -1208,8 +1208,110 @@ impl<T: ?Sized> AsPointerDyn<T> for Rc<RefCell<T>> { |
1208 | 1208 | } |
1209 | 1209 | } |
1210 | 1210 |
|
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 | +} |
1213 | 1315 |
|
1214 | 1316 | #[cfg(test)] |
1215 | 1317 | mod tests { |
|
0 commit comments