Skip to content

Commit

Permalink
Fix memory leak on beef::lean::Cow
Browse files Browse the repository at this point in the history
  • Loading branch information
maciejhirsz committed Mar 18, 2020
1 parent 41a9d1d commit 2e75601
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 6 deletions.
26 changes: 26 additions & 0 deletions src/fat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,30 @@ impl Capacity for Wide {
fn maybe(_: usize, capacity: Option<NonZeroUsize>) -> Option<NonZeroUsize> {
capacity
}
}

#[cfg(test)]
mod tests {
use super::Cow;

#[test]
fn stress_test_owned() {
let mut expected = String::from("Hello... ");
let mut cow: Cow<str> = Cow::borrowed("Hello... ");

for i in 0..1024 {
if i % 3 == 0 {
cow = cow.clone();
}

let mut owned = cow.into_owned();

expected.push_str("Hello?.. ");
owned.push_str("Hello?.. ");

cow = owned.into();
}

assert_eq!(expected, cow.into_owned());
}
}
11 changes: 7 additions & 4 deletions src/lean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ mod internal {
use internal::Lean;

const MASK_LO: usize = u32::max_value() as usize;
const MASK_HI: usize = !u32::max_value() as usize;
const MASK_HI: usize = !(u32::max_value() as usize);

impl Capacity for Lean {
type Field = Lean;
Expand All @@ -40,14 +40,14 @@ impl Capacity for Lean {

#[inline]
fn store<T>(ptr: *mut T, len: usize, capacity: usize) -> (*mut [T], Lean) {
if capacity > MASK_LO {
if capacity & MASK_HI != 0 {
panic!("beef::lean::Cow: Capacity out of bounds");
}

(
slice_from_raw_parts_mut(
ptr,
(len & MASK_LO) | ((capacity & MASK_HI) << 32),
(len & MASK_LO) | ((capacity & MASK_LO) << 32),
),
Lean,
)
Expand Down Expand Up @@ -79,7 +79,10 @@ mod tests {

for i in 0..1024 {
if i % 3 == 0 {
cow = cow.clone();
let mut old = std::mem::ManuallyDrop::new(cow);
cow = (*old).clone();

unsafe { std::mem::ManuallyDrop::drop(&mut old); }

This comment has been minimized.

Copy link
@RalfJung

RalfJung Mar 18, 2020

Contributor

Why use unsafe code here? This should be the same as just doing let old = cow; above, and drop(old) here (and you can even leave away the latter).

}

let mut owned = cow.into_owned();
Expand Down
4 changes: 2 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub(crate) mod internal {
where
U: Capacity,
{
let len = (*inner.as_ptr()).len();
let len = (&*inner.as_ptr()).len();
let (len, cap) = U::unpack(len, capacity);

String::from_utf8_unchecked(
Expand Down Expand Up @@ -154,7 +154,7 @@ pub(crate) mod internal {
where
U: Capacity,
{
let len = (*inner.as_ptr()).len();
let len = (&*inner.as_ptr()).len();
let (len, cap) = U::unpack(len, capacity);

Vec::from_raw_parts(inner.cast().as_ptr(), len, cap)
Expand Down

0 comments on commit 2e75601

Please sign in to comment.