Fix improper handling of overflow in len_usize (fix #128)

This will lead to implausibly large lengths, nearly endless iterators
and possibly unsound behaviour through the Drop implementation

Switches the `truncate` method to refer to the common defintion of
simply chopping of the test bits. (Implemented by `as`, which is defined
to do this).

Adds a new `saturate` method to replace the previous `truncate` method
This commit is contained in:
David Sawatzke 2019-11-29 10:42:57 +01:00
parent 5ffd0df2cc
commit fedcf84cb4
2 changed files with 39 additions and 10 deletions

View File

@ -21,6 +21,9 @@ unsafe impl XCore for MultiCore {
} }
pub unsafe trait Uxx: Into<usize> + Send { pub unsafe trait Uxx: Into<usize> + Send {
#[doc(hidden)]
fn saturate(x: usize) -> Self;
#[doc(hidden)] #[doc(hidden)]
fn truncate(x: usize) -> Self; fn truncate(x: usize) -> Self;
@ -39,15 +42,19 @@ pub unsafe trait Uxx: Into<usize> + Send {
} }
unsafe impl Uxx for u8 { unsafe impl Uxx for u8 {
fn truncate(x: usize) -> Self { fn saturate(x: usize) -> Self {
let max = ::core::u8::MAX; let max = Self::max_value() as usize;
if x >= usize::from(max) { if x >= usize::from(max) {
max max as Self
} else { } else {
x as u8 x as Self
} }
} }
fn truncate(x: usize) -> Self {
x as Self
}
unsafe fn load_acquire<C>(x: *const Self) -> Self unsafe fn load_acquire<C>(x: *const Self) -> Self
where where
C: XCore, C: XCore,
@ -79,15 +86,19 @@ unsafe impl Uxx for u8 {
} }
unsafe impl Uxx for u16 { unsafe impl Uxx for u16 {
fn truncate(x: usize) -> Self { fn saturate(x: usize) -> Self {
let max = ::core::u16::MAX; let max = Self::max_value() as usize;
if x >= usize::from(max) { if x >= usize::from(max) {
max max as Self
} else { } else {
x as u16 x as Self
} }
} }
fn truncate(x: usize) -> Self {
x as Self
}
unsafe fn load_acquire<C>(x: *const Self) -> Self unsafe fn load_acquire<C>(x: *const Self) -> Self
where where
C: XCore, C: XCore,
@ -119,6 +130,10 @@ unsafe impl Uxx for u16 {
} }
unsafe impl Uxx for usize { unsafe impl Uxx for usize {
fn saturate(x: usize) -> Self {
x
}
fn truncate(x: usize) -> Self { fn truncate(x: usize) -> Self {
x x
} }

View File

@ -174,7 +174,7 @@ where
{ {
/// Returns the maximum number of elements the queue can hold /// Returns the maximum number of elements the queue can hold
pub fn capacity(&self) -> U { pub fn capacity(&self) -> U {
U::truncate(N::to_usize()) U::saturate(N::to_usize())
} }
/// Returns `true` if the queue has a length of 0 /// Returns `true` if the queue has a length of 0
@ -205,7 +205,7 @@ where
let head = self.0.head.load_relaxed().into(); let head = self.0.head.load_relaxed().into();
let tail = self.0.tail.load_relaxed().into(); let tail = self.0.tail.load_relaxed().into();
tail.wrapping_sub(head) U::truncate(tail.wrapping_sub(head)).into()
} }
} }
@ -693,6 +693,20 @@ mod tests {
assert_eq!(items.next(), None); assert_eq!(items.next(), None);
} }
#[test]
fn iter_overflow() {
let mut rb: Queue<i32, U4, u8> = Queue::u8();
rb.enqueue(0).unwrap();
for _ in 0..300 {
let mut items = rb.iter_mut();
assert_eq!(items.next(), Some(&mut 0));
assert_eq!(items.next(), None);
rb.dequeue().unwrap();
rb.enqueue(0).unwrap();
}
}
#[test] #[test]
fn iter_mut() { fn iter_mut() {
let mut rb: Queue<i32, U4> = Queue::new(); let mut rb: Queue<i32, U4> = Queue::new();