Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Run destructors when clearing PinVec #21

Merged
merged 4 commits into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/pin_slab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,6 @@ impl<T> Default for PinSlab<T> {
}
}

impl<T> Drop for PinSlab<T> {
fn drop(&mut self) {
self.clear();
}
}

#[cfg(test)]
mod tests {
use super::PinSlab;
Expand Down
35 changes: 35 additions & 0 deletions src/pin_vec.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::mem::{self, MaybeUninit};
use std::ops::{Index, IndexMut};
use std::ptr::drop_in_place;

pub struct PinVec<T> {
// Slots of memory. Once one has been allocated it is never moved.
Expand All @@ -22,6 +23,12 @@ impl<T> PinVec<T> {
}

pub fn clear(&mut self) {
udoprog marked this conversation as resolved.
Show resolved Hide resolved
for i in 0..self.len {
// Safety: we know the pointer is initialized because its index is in bounds, and it
// can be dropped because we are emptying the container, which means these contents
// will not be accessed again.
unsafe { drop_in_place(self.get_mut(i).unwrap()) }
}
self.slots.clear();
self.len = 0;
}
Expand Down Expand Up @@ -66,6 +73,12 @@ impl<T> PinVec<T> {
}
}

impl<T> Drop for PinVec<T> {
fn drop(&mut self) {
self.clear();
}
}

impl<T> Index<usize> for PinVec<T> {
type Output = T;

Expand Down Expand Up @@ -106,6 +119,8 @@ const fn calculate_key(key: usize) -> (usize, usize, usize) {
mod tests {
use crate::pin_vec::calculate_key;

use super::PinVec;

#[test]
fn key_test() {
// NB: range of the first slot.
Expand All @@ -121,4 +136,24 @@ mod tests {
);
}
}

#[test]
fn run_destructors() {
let mut destructor_ran = false;

struct RunDestructor<'a>(&'a mut bool);
impl<'a> Drop for RunDestructor<'a> {
fn drop(&mut self) {
*self.0 = true;
}
}

{
// Make sure PinVec runs the destructors
let mut v = PinVec::new();
v.push(RunDestructor(&mut destructor_ran));
}

assert!(destructor_ran);
}
}
17 changes: 17 additions & 0 deletions tests/pin_slab_memory_leak.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use unicycle::pin_slab::PinSlab;

struct Foo(u32);

struct Bar(Vec<u32>);

#[global_allocator]
static ALLOCATOR: checkers::Allocator = checkers::Allocator::system();

#[checkers::test]
fn test_pin_slab_memory_leak() {
let mut copy = PinSlab::new();
copy.insert(Foo(42));

let mut non_copy = PinSlab::new();
non_copy.insert(Bar(vec![42]));
}