Skip to content

Commit bdd07bf

Browse files
committed
Fix layout differences of Header<Atomic> v.s. Header<NonAtomic>
This fixes #58, which shows UB when converting between non-atomic and atomic `Tendril`. This conversion is exposed without `unsafe` through `SendTendril` and implemented with `transmute`, so matching layout is essential.
1 parent cd133fe commit bdd07bf

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

src/tendril.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,25 @@ pub unsafe trait Atomicity: 'static {
6969
///
7070
/// This is akin to using `Rc` for reference counting.
7171
#[repr(C)]
72-
pub struct NonAtomic(Cell<PackedUsize>);
73-
74-
#[repr(C, packed)]
75-
#[derive(Copy, Clone)]
76-
struct PackedUsize(usize);
72+
pub struct NonAtomic(Cell<usize>);
7773

7874
unsafe impl Atomicity for NonAtomic {
7975
#[inline]
8076
fn new() -> Self {
81-
NonAtomic(Cell::new(PackedUsize(1)))
77+
NonAtomic(Cell::new(1))
8278
}
8379

8480
#[inline]
8581
fn increment(&self) -> usize {
86-
let value = self.0.get().0;
87-
self.0.set(PackedUsize(value.checked_add(1).expect(OFLOW)));
82+
let value = self.0.get();
83+
self.0.set(value.checked_add(1).expect(OFLOW));
8884
value
8985
}
9086

9187
#[inline]
9288
fn decrement(&self) -> usize {
93-
let value = self.0.get().0;
94-
self.0.set(PackedUsize(value - 1));
89+
let value = self.0.get();
90+
self.0.set(value - 1);
9591
value
9692
}
9793

@@ -130,6 +126,7 @@ unsafe impl Atomicity for Atomic {
130126
}
131127
}
132128

129+
#[repr(C)] // Preserve field order for cross-atomicity transmutes
133130
struct Header<A: Atomicity> {
134131
refcount: A,
135132
cap: u32,
@@ -1712,7 +1709,7 @@ mod test {
17121709
mem::size_of::<Header<Atomic>>(),
17131710
);
17141711
assert_eq!(
1715-
mem::size_of::<*const ()>() + 4,
1712+
mem::size_of::<Header<Atomic>>(),
17161713
mem::size_of::<Header<NonAtomic>>(),
17171714
);
17181715
}
@@ -2448,6 +2445,16 @@ mod test {
24482445
assert_eq!("this is a string", &*t);
24492446
}
24502447

2448+
/// https://github.com/servo/tendril/issues/58
2449+
#[test]
2450+
fn issue_58() {
2451+
let data = "<p><i>Hello!</p>, World!</i>";
2452+
let s: Tendril<fmt::UTF8, NonAtomic> = data.into();
2453+
assert_eq!(&*s, data);
2454+
let s: Tendril<fmt::UTF8, Atomic> = s.into_send().into();
2455+
assert_eq!(&*s, data);
2456+
}
2457+
24512458
#[test]
24522459
fn inline_send() {
24532460
let s = "x".to_tendril();

0 commit comments

Comments
 (0)