Skip to content

Commit

Permalink
Fix possible undefined behavior in primitive list as_slice
Browse files Browse the repository at this point in the history
  • Loading branch information
as-com authored and dwrensha committed May 12, 2024
1 parent 203b8de commit 929cd4e
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 2 deletions.
21 changes: 19 additions & 2 deletions capnp/src/primitive_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
//! List of primitives.
use core::marker;
use core::ptr::NonNull;

use crate::introspect;
use crate::private::layout::{
Expand Down Expand Up @@ -124,7 +125,16 @@ impl<'a, T: PrimitiveElement> Reader<'a, T> {
// This is a List(Void).
self.len() as usize
};
Some(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *mut T, slice_length) })
Some(unsafe {
core::slice::from_raw_parts(
if slice_length == 0 {
NonNull::dangling().as_ptr()
} else {
bytes.as_ptr() as *mut T
},
slice_length,
)
})
} else {
None
}
Expand Down Expand Up @@ -184,7 +194,14 @@ where
self.len() as usize
};
Some(unsafe {
core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, slice_length)
core::slice::from_raw_parts_mut(
if slice_length == 0 {
NonNull::dangling().as_ptr()
} else {
bytes.as_mut_ptr() as *mut T
},
slice_length,
)
})
} else {
None
Expand Down
90 changes: 90 additions & 0 deletions capnp/tests/primitive_list_as_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ pub fn primitive_list_as_slice() {
assert_eq!(u8list.as_slice().unwrap(), &[0, 1, 2]);
}

{
let mut u16list = msg.initn_root::<primitive_list::Builder<u16>>(0);
assert_eq!(u16list.as_slice().unwrap().len(), 0);
assert_eq!(u16list.into_reader().as_slice().unwrap().len(), 0);
}

{
let mut u16list = msg.initn_root::<primitive_list::Builder<u16>>(4);
u16list.set(0, 0xab);
Expand All @@ -48,6 +54,90 @@ pub fn primitive_list_as_slice() {
);
}

{
let mut u32list = msg.initn_root::<primitive_list::Builder<u32>>(0);
assert_eq!(u32list.as_slice().unwrap().len(), 0);
assert_eq!(u32list.into_reader().as_slice().unwrap().len(), 0);
}

{
let mut u32list = msg.initn_root::<primitive_list::Builder<u32>>(4);
u32list.set(0, 0xab);
u32list.set(1, 0xcd);
u32list.set(2, 0xde);
u32list.set(3, 0xff);
assert_eq!(u32list.as_slice().unwrap(), &[0xab, 0xcd, 0xde, 0xff]);
assert_eq!(
u32list.into_reader().as_slice().unwrap(),
&[0xab, 0xcd, 0xde, 0xff]
);
}

{
let mut u64list = msg.initn_root::<primitive_list::Builder<u64>>(0);
assert_eq!(u64list.as_slice().unwrap().len(), 0);
assert_eq!(u64list.into_reader().as_slice().unwrap().len(), 0);
}

{
let mut u64list = msg.initn_root::<primitive_list::Builder<u64>>(4);
u64list.set(0, 0xab);
u64list.set(1, 0xcd);
u64list.set(2, 0xde);
u64list.set(3, 0xff);
assert_eq!(u64list.as_slice().unwrap(), &[0xab, 0xcd, 0xde, 0xff]);
assert_eq!(
u64list.into_reader().as_slice().unwrap(),
&[0xab, 0xcd, 0xde, 0xff]
);
}

{
let mut f32list = msg.initn_root::<primitive_list::Builder<f32>>(0);
assert_eq!(f32list.as_slice().unwrap().len(), 0);
assert_eq!(f32list.into_reader().as_slice().unwrap().len(), 0);
}

{
let mut f32list = msg.initn_root::<primitive_list::Builder<f32>>(5);
f32list.set(0, 0.3);
f32list.set(1, 0.0);
f32list.set(2, f32::NEG_INFINITY);
f32list.set(3, -0.0);
f32list.set(4, f32::MAX);
assert_eq!(
f32list.as_slice().unwrap(),
&[0.3, 0.0, f32::NEG_INFINITY, -0.0, f32::MAX]
);
assert_eq!(
f32list.into_reader().as_slice().unwrap(),
&[0.3, 0.0, f32::NEG_INFINITY, -0.0, f32::MAX]
);
}

{
let mut f64list = msg.initn_root::<primitive_list::Builder<f64>>(0);
assert_eq!(f64list.as_slice().unwrap().len(), 0);
assert_eq!(f64list.into_reader().as_slice().unwrap().len(), 0);
}

{
let mut f64list = msg.initn_root::<primitive_list::Builder<f64>>(5);
f64list.set(0, 0.3);
f64list.set(1, 0.0);
f64list.set(2, f64::NEG_INFINITY);
f64list.set(3, -0.0);
f64list.set(4, f64::MAX);
assert_eq!(
f64list.as_slice().unwrap(),
&[0.3, 0.0, f64::NEG_INFINITY, -0.0, f64::MAX]
);
assert_eq!(
f64list.into_reader().as_slice().unwrap(),
&[0.3, 0.0, f64::NEG_INFINITY, -0.0, f64::MAX]
);
}

{
// Test the case when the list elements are InlineComposite.
use capnp::{schema_capnp, struct_list};
Expand Down

0 comments on commit 929cd4e

Please sign in to comment.