Skip to content

Commit 929cd4e

Browse files
as-comdwrensha
authored andcommitted
Fix possible undefined behavior in primitive list as_slice
1 parent 203b8de commit 929cd4e

File tree

2 files changed

+109
-2
lines changed

2 files changed

+109
-2
lines changed

capnp/src/primitive_list.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
//! List of primitives.
2323
2424
use core::marker;
25+
use core::ptr::NonNull;
2526

2627
use crate::introspect;
2728
use crate::private::layout::{
@@ -124,7 +125,16 @@ impl<'a, T: PrimitiveElement> Reader<'a, T> {
124125
// This is a List(Void).
125126
self.len() as usize
126127
};
127-
Some(unsafe { core::slice::from_raw_parts(bytes.as_ptr() as *mut T, slice_length) })
128+
Some(unsafe {
129+
core::slice::from_raw_parts(
130+
if slice_length == 0 {
131+
NonNull::dangling().as_ptr()
132+
} else {
133+
bytes.as_ptr() as *mut T
134+
},
135+
slice_length,
136+
)
137+
})
128138
} else {
129139
None
130140
}
@@ -184,7 +194,14 @@ where
184194
self.len() as usize
185195
};
186196
Some(unsafe {
187-
core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, slice_length)
197+
core::slice::from_raw_parts_mut(
198+
if slice_length == 0 {
199+
NonNull::dangling().as_ptr()
200+
} else {
201+
bytes.as_mut_ptr() as *mut T
202+
},
203+
slice_length,
204+
)
188205
})
189206
} else {
190207
None

capnp/tests/primitive_list_as_slice.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ pub fn primitive_list_as_slice() {
3535
assert_eq!(u8list.as_slice().unwrap(), &[0, 1, 2]);
3636
}
3737

38+
{
39+
let mut u16list = msg.initn_root::<primitive_list::Builder<u16>>(0);
40+
assert_eq!(u16list.as_slice().unwrap().len(), 0);
41+
assert_eq!(u16list.into_reader().as_slice().unwrap().len(), 0);
42+
}
43+
3844
{
3945
let mut u16list = msg.initn_root::<primitive_list::Builder<u16>>(4);
4046
u16list.set(0, 0xab);
@@ -48,6 +54,90 @@ pub fn primitive_list_as_slice() {
4854
);
4955
}
5056

57+
{
58+
let mut u32list = msg.initn_root::<primitive_list::Builder<u32>>(0);
59+
assert_eq!(u32list.as_slice().unwrap().len(), 0);
60+
assert_eq!(u32list.into_reader().as_slice().unwrap().len(), 0);
61+
}
62+
63+
{
64+
let mut u32list = msg.initn_root::<primitive_list::Builder<u32>>(4);
65+
u32list.set(0, 0xab);
66+
u32list.set(1, 0xcd);
67+
u32list.set(2, 0xde);
68+
u32list.set(3, 0xff);
69+
assert_eq!(u32list.as_slice().unwrap(), &[0xab, 0xcd, 0xde, 0xff]);
70+
assert_eq!(
71+
u32list.into_reader().as_slice().unwrap(),
72+
&[0xab, 0xcd, 0xde, 0xff]
73+
);
74+
}
75+
76+
{
77+
let mut u64list = msg.initn_root::<primitive_list::Builder<u64>>(0);
78+
assert_eq!(u64list.as_slice().unwrap().len(), 0);
79+
assert_eq!(u64list.into_reader().as_slice().unwrap().len(), 0);
80+
}
81+
82+
{
83+
let mut u64list = msg.initn_root::<primitive_list::Builder<u64>>(4);
84+
u64list.set(0, 0xab);
85+
u64list.set(1, 0xcd);
86+
u64list.set(2, 0xde);
87+
u64list.set(3, 0xff);
88+
assert_eq!(u64list.as_slice().unwrap(), &[0xab, 0xcd, 0xde, 0xff]);
89+
assert_eq!(
90+
u64list.into_reader().as_slice().unwrap(),
91+
&[0xab, 0xcd, 0xde, 0xff]
92+
);
93+
}
94+
95+
{
96+
let mut f32list = msg.initn_root::<primitive_list::Builder<f32>>(0);
97+
assert_eq!(f32list.as_slice().unwrap().len(), 0);
98+
assert_eq!(f32list.into_reader().as_slice().unwrap().len(), 0);
99+
}
100+
101+
{
102+
let mut f32list = msg.initn_root::<primitive_list::Builder<f32>>(5);
103+
f32list.set(0, 0.3);
104+
f32list.set(1, 0.0);
105+
f32list.set(2, f32::NEG_INFINITY);
106+
f32list.set(3, -0.0);
107+
f32list.set(4, f32::MAX);
108+
assert_eq!(
109+
f32list.as_slice().unwrap(),
110+
&[0.3, 0.0, f32::NEG_INFINITY, -0.0, f32::MAX]
111+
);
112+
assert_eq!(
113+
f32list.into_reader().as_slice().unwrap(),
114+
&[0.3, 0.0, f32::NEG_INFINITY, -0.0, f32::MAX]
115+
);
116+
}
117+
118+
{
119+
let mut f64list = msg.initn_root::<primitive_list::Builder<f64>>(0);
120+
assert_eq!(f64list.as_slice().unwrap().len(), 0);
121+
assert_eq!(f64list.into_reader().as_slice().unwrap().len(), 0);
122+
}
123+
124+
{
125+
let mut f64list = msg.initn_root::<primitive_list::Builder<f64>>(5);
126+
f64list.set(0, 0.3);
127+
f64list.set(1, 0.0);
128+
f64list.set(2, f64::NEG_INFINITY);
129+
f64list.set(3, -0.0);
130+
f64list.set(4, f64::MAX);
131+
assert_eq!(
132+
f64list.as_slice().unwrap(),
133+
&[0.3, 0.0, f64::NEG_INFINITY, -0.0, f64::MAX]
134+
);
135+
assert_eq!(
136+
f64list.into_reader().as_slice().unwrap(),
137+
&[0.3, 0.0, f64::NEG_INFINITY, -0.0, f64::MAX]
138+
);
139+
}
140+
51141
{
52142
// Test the case when the list elements are InlineComposite.
53143
use capnp::{schema_capnp, struct_list};

0 commit comments

Comments
 (0)