Skip to content

Commit

Permalink
✨ Forbid zero sized type
Browse files Browse the repository at this point in the history
  • Loading branch information
arthurlm committed Oct 22, 2023
1 parent d419131 commit 3e17d68
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ use std::marker::PhantomData;
pub use segment::Segment;
pub use segment_builder::{DefaultSegmentBuilder, SegmentBuilder};
pub use stats::MmapStats;
use utils::check_zst;
pub use vec_builder::MmapVecBuilder;

#[cfg(feature = "serde")]
Expand Down Expand Up @@ -157,6 +158,8 @@ where
/// Create a zero size mmap vec.
#[inline(always)]
pub fn new() -> Self {
check_zst::<T>();

let builder = B::default();
let path = builder.new_segment_path();
Self {
Expand Down
7 changes: 6 additions & 1 deletion src/segment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{

use crate::{
stats::{COUNT_ACTIVE_SEGMENT, COUNT_FTRUNCATE_FAILED, COUNT_MMAP_FAILED, COUNT_MUNMAP_FAILED},
utils::page_size,
utils::{check_zst, page_size},
};

/// Segment is a constant slice of type T that is memory mapped to disk.
Expand All @@ -29,6 +29,7 @@ impl<T> Segment<T> {
/// Create a zero size segment.
#[inline(always)]
pub const fn null() -> Self {
check_zst::<T>();
Self {
addr: std::ptr::null_mut(),
len: 0,
Expand All @@ -40,6 +41,7 @@ impl<T> Segment<T> {
///
/// File will be created and init with computed capacity.
pub fn open_rw<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> {
check_zst::<T>();
if capacity == 0 {
return Ok(Self::null());
}
Expand Down Expand Up @@ -284,6 +286,7 @@ unsafe impl<T> Send for Segment<T> {}
unsafe impl<T> Sync for Segment<T> {}

unsafe fn ftruncate<T>(file: &File, capacity: usize) -> io::Result<()> {
check_zst::<T>();
let segment_size = capacity * mem::size_of::<T>();
let fd = file.as_raw_fd();

Expand All @@ -296,6 +299,7 @@ unsafe fn ftruncate<T>(file: &File, capacity: usize) -> io::Result<()> {
}

unsafe fn mmap<T>(file: &File, capacity: usize) -> io::Result<*mut T> {
check_zst::<T>();
let segment_size = capacity * mem::size_of::<T>();

// It is safe to not keep a reference to the initial file descriptor.
Expand All @@ -321,6 +325,7 @@ unsafe fn mmap<T>(file: &File, capacity: usize) -> io::Result<*mut T> {
}

unsafe fn munmap<T>(addr: *mut T, capacity: usize) -> io::Result<()> {
check_zst::<T>();
debug_assert!(!addr.is_null());
debug_assert!(capacity > 0);

Expand Down
8 changes: 8 additions & 0 deletions src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
use std::mem;

pub fn page_size() -> usize {
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
}

pub const fn check_zst<T>() {
if mem::size_of::<T>() == 0 {
panic!("Zero sized type are not supported with MmapVec. What is the point of mapping ZST to disk ?");
}
}
6 changes: 5 additions & 1 deletion src/vec_builder.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use std::{io, marker::PhantomData, mem};

use crate::{utils::page_size, DefaultSegmentBuilder, MmapVec, Segment, SegmentBuilder};
use crate::{
utils::{check_zst, page_size},
DefaultSegmentBuilder, MmapVec, Segment, SegmentBuilder,
};

/// Helps to create vec with custom parameters.
///
Expand Down Expand Up @@ -62,6 +65,7 @@ impl<T, SB: SegmentBuilder> MmapVecBuilder<T, SB> {
impl<T, SB: SegmentBuilder> Default for MmapVecBuilder<T, SB> {
#[inline(always)]
fn default() -> Self {
check_zst::<T>();
Self {
segment_builder: SB::default(),
capacity: page_size() / mem::size_of::<T>(),
Expand Down
8 changes: 8 additions & 0 deletions tests/test_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,3 +392,11 @@ fn test_try_from_vec() {
let vec = MmapVec::<_, DefaultSegmentBuilder>::try_from(Vec::from([8, 6, 4, -48, 16])).unwrap();
assert_eq!(&vec[..], [8, 6, 4, -48, 16]);
}

#[test]
#[should_panic = "Zero sized type are not supported"]
fn test_zero_sized_type() {
struct VoidStruct;

let _vec = MmapVec::<VoidStruct>::with_capacity(50).unwrap();
}

0 comments on commit 3e17d68

Please sign in to comment.