Skip to content

Commit a9dae40

Browse files
committed
libcc2rs: fix pointer comparison of adjacent fields in the same allocation
1 parent 60266be commit a9dae40

3 files changed

Lines changed: 118 additions & 6 deletions

File tree

‎libcc2rs/src/field.rs‎

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ impl<S: Record> FieldPtr<S> for Ptr<S> {
274274
PtrKind::Field(_, _, FieldShape::Single) => {
275275
self.field_ptr(get, get_mut, offset).decay()
276276
}
277-
_ => self.elems_of(get, get_mut, offset(&S::OFFSETS)),
277+
_ => self.elems_of(get, get_mut, offset(&S::OFFSETS), true),
278278
}
279279
}
280280
}
@@ -290,7 +290,8 @@ impl<S: Record> Ptr<S> {
290290
// A pointer to the first element of the array or vector that `get` gives
291291
// in the struct that self points to, which is at byte `offset` of the
292292
// struct. The pointer reaches the array or vector through the Value that
293-
// holds the struct, or else through self.
293+
// holds the struct, or else through self. `inline` tells if the elements
294+
// are in the memory of the struct, as those of an array are.
294295
// The projection of an array of structs takes the array as a Box, the
295296
// contents of its Value.
296297
#[allow(clippy::borrowed_box)]
@@ -300,6 +301,7 @@ impl<S: Record> Ptr<S> {
300301
get: impl Fn(&S) -> &C + 'static,
301302
get_mut: impl Fn(&mut S) -> &mut C + 'static,
302303
offset: usize,
304+
inline: bool,
303305
) -> Ptr<T>
304306
where
305307
C: AsRef<[T]> + AsMut<[T]> + 'static,
@@ -318,18 +320,21 @@ impl<S: Record> Ptr<S> {
318320
move |s: &S| get(s).as_ref(),
319321
move |s: &mut S| get_mut(s).as_mut(),
320322
address(w.as_ptr() as *const ()),
323+
inline,
321324
)),
322325
PtrKind::StackArray(w) | PtrKind::HeapArray(w) => Rc::new(InValue::new(
323326
w,
324327
move |a: &Box<[S]>| get(&a[idx]).as_ref(),
325328
move |a: &mut Box<[S]>| get_mut(&mut a[idx]).as_mut(),
326329
address(w.as_ptr() as *const ()),
330+
inline,
327331
)),
328332
PtrKind::StackVec(w) | PtrKind::HeapVec(w) => Rc::new(InValue::new(
329333
w,
330334
move |v: &Vec<S>| get(&v[idx]).as_ref(),
331335
move |v: &mut Vec<S>| get_mut(&mut v[idx]).as_mut(),
332336
address(w.as_ptr() as *const ()),
337+
inline,
333338
)),
334339
_ => Rc::new(FieldOf::new(
335340
self.clone(),
@@ -355,11 +360,13 @@ struct InValue<R, G, M> {
355360
get_mut: M,
356361
// The address of the field, for comparisons.
357362
address: usize,
363+
// Whether the elements are in the memory of the struct.
364+
inline: bool,
358365
}
359366

360367
impl<R, G, M> InValue<R, G, M> {
361368
#[inline]
362-
fn new<T>(root: &Weak<RefCell<R>>, get: G, get_mut: M, address: usize) -> Self
369+
fn new<T>(root: &Weak<RefCell<R>>, get: G, get_mut: M, address: usize, inline: bool) -> Self
363370
where
364371
G: Fn(&R) -> &[T],
365372
M: Fn(&mut R) -> &mut [T],
@@ -369,6 +376,7 @@ impl<R, G, M> InValue<R, G, M> {
369376
get,
370377
get_mut,
371378
address,
379+
inline,
372380
}
373381
}
374382
}
@@ -404,6 +412,11 @@ where
404412
fn address(&self) -> usize {
405413
self.address
406414
}
415+
416+
fn struct_root(&self) -> Option<usize> {
417+
self.inline
418+
.then_some(self.root.as_ptr() as *const () as usize)
419+
}
407420
}
408421

409422
// A field of a struct, as returned by field_ref!, which is made a pointer to
@@ -445,7 +458,7 @@ where
445458
.decay(),
446459
_ => self
447460
.base
448-
.elems_of(self.get, self.get_mut, (self.offset)(&S::OFFSETS)),
461+
.elems_of(self.get, self.get_mut, (self.offset)(&S::OFFSETS), false),
449462
}
450463
}
451464
}
@@ -1586,6 +1599,70 @@ mod tests {
15861599
assert_eq!(v.offset(1).read(), 6);
15871600
}
15881601

1602+
#[derive(Clone, Default, Record, ByteRepr)]
1603+
#[byte_size(44)]
1604+
struct Adjacent {
1605+
#[offset(0)]
1606+
#[byte_size(8)]
1607+
a: Box<[i32]>,
1608+
#[offset(8)]
1609+
#[byte_size(8)]
1610+
b: Box<[i32]>,
1611+
#[offset(16)]
1612+
#[byte_size(24)]
1613+
v: Vec<i32>,
1614+
#[offset(40)]
1615+
c: i32,
1616+
}
1617+
1618+
#[derive(Default, Record, ByteRepr)]
1619+
#[byte_size(48)]
1620+
struct HoldsAdjacent {
1621+
#[offset(0)]
1622+
n: i32,
1623+
#[offset(4)]
1624+
#[byte_size(44)]
1625+
adj: Adjacent,
1626+
}
1627+
1628+
fn adjacent() -> Adjacent {
1629+
Adjacent {
1630+
a: vec![1, 2].into_boxed_slice(),
1631+
b: vec![3, 4].into_boxed_slice(),
1632+
v: vec![5, 6, 7, 8, 9, 10],
1633+
c: 11,
1634+
}
1635+
}
1636+
1637+
fn check_adjacent(s: Ptr<Adjacent>) {
1638+
// One past the end of an array field is the next field.
1639+
let a: Ptr<i32> = array_field_ptr!(s, a);
1640+
let b: Ptr<i32> = array_field_ptr!(s, b);
1641+
assert_eq!(a.offset(2), b);
1642+
assert!(a.offset(2) <= b && a.offset(2) >= b);
1643+
assert!(a.offset(1) < b && b < a.offset(3));
1644+
assert_ne!(a.offset(1), b);
1645+
assert_eq!(b.offset(-2), a);
1646+
// The elements of a vector are not in the struct.
1647+
let v: Ptr<i32> = field_ref!(s, v).as_pointer();
1648+
assert_ne!(v.offset(6), field_ptr!(s, c));
1649+
}
1650+
1651+
#[test]
1652+
fn adjacent_array_fields() {
1653+
let s: Value<Adjacent> = Rc::new(RefCell::new(adjacent()));
1654+
check_adjacent(s.as_pointer());
1655+
let held: Value<HoldsAdjacent> = Rc::new(RefCell::new(HoldsAdjacent {
1656+
n: 0,
1657+
adj: adjacent(),
1658+
}));
1659+
check_adjacent(field_ptr!(held, adj));
1660+
// Fields of different structs are not equal.
1661+
let other: Value<Adjacent> = Rc::new(RefCell::new(adjacent()));
1662+
let a: Ptr<i32> = array_field_ptr!(s, a);
1663+
assert_ne!(a.offset(2), array_field_ptr!(other, b));
1664+
}
1665+
15891666
#[test]
15901667
fn pointer_size() {
15911668
// Pointers to elements of fields are no larger than other pointers.

‎libcc2rs/src/rc.rs‎

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ pub trait SliceParent<T> {
5151
fn borrow_slice_mut<'a>(&self, root: &'a SliceRoot) -> RefMut<'a, [T]>;
5252
fn address(&self) -> usize;
5353

54+
// The address of the allocation of the struct that the elements are in,
55+
// if they are in its memory, as the elements of an array field are.
56+
fn struct_root(&self) -> Option<usize> {
57+
None
58+
}
59+
5460
// Calls `f` with element `idx`.
5561
fn with_elem(&self, idx: usize, f: &mut dyn FnMut(&T)) {
5662
let root = self.root();
@@ -342,6 +348,27 @@ impl<T> PtrKind<T> {
342348
PtrKind::Reinterpreted(data) => data.alloc.address(),
343349
}
344350
}
351+
352+
// The address of the allocation of the struct that the pointer points
353+
// into, if it points to a field or to an element of an array field, which
354+
// are at their address in the struct.
355+
fn struct_root(&self) -> Option<usize> {
356+
match self {
357+
PtrKind::Field(root, _, FieldShape::Single | FieldShape::Array) => {
358+
Some(root.as_ptr() as *const () as usize)
359+
}
360+
PtrKind::Nested(parent) => parent.struct_root(),
361+
_ => None,
362+
}
363+
}
364+
365+
// Whether both pointers point into the same struct, where they are
366+
// compared by their address, e.g., one past the end of an array field is
367+
// the next field.
368+
fn in_same_struct(&self, other: &Self) -> bool {
369+
self.struct_root()
370+
.is_some_and(|root| other.struct_root() == Some(root))
371+
}
345372
}
346373

347374
impl<T> Eq for PtrKind<T> {}
@@ -390,7 +417,13 @@ impl<T> Clone for Ptr<T> {
390417

391418
impl<T> PartialEq for Ptr<T> {
392419
fn eq(&self, other: &Self) -> bool {
393-
self.byte_offset() == other.byte_offset() && self.kind == other.kind
420+
if self.byte_offset() == other.byte_offset() {
421+
return self.kind == other.kind;
422+
}
423+
match (&self.kind, &other.kind) {
424+
(PtrKind::Nested(a), PtrKind::Nested(b)) if Rc::ptr_eq(a, b) => false,
425+
(a, b) => a.in_same_struct(b) && self.address() == other.address(),
426+
}
394427
}
395428
}
396429

@@ -400,6 +433,9 @@ impl<T> Ord for Ptr<T> {
400433
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
401434
match self.kind.partial_cmp(&other.kind) {
402435
Some(std::cmp::Ordering::Equal) | None => self.byte_offset().cmp(&other.byte_offset()),
436+
Some(_) if self.kind.in_same_struct(&other.kind) => {
437+
self.address().cmp(&other.address())
438+
}
403439
Some(ord) => ord,
404440
}
405441
}

‎tests/unit/struct_member_array_adjacency.c‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// panic: refcount
21
#include <assert.h>
32

43
struct pair {

0 commit comments

Comments
 (0)