Skip to content

Commit 691b15f

Browse files
committed
Ensure we comply with the non-NULL req for slice::from_raw_parts
When building a slice with `slice::from_raw_parts`, we're required to pass in a non-NULL pointer even if the length is 0. While we did this in most cases, we weren't always careful about it. Here we fix the issue by using a simple wrapper which passes a dummy pointer instead.
1 parent d31c8f6 commit 691b15f

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

c-bindings-gen/src/blocks.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,13 +226,13 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
226226
writeln!(w, "impl {} {{", mangled_container).unwrap();
227227
writeln!(w, "\t#[allow(unused)] pub(crate) fn into_rust(&mut self) -> Vec<{}> {{", inner_type).unwrap();
228228
writeln!(w, "\t\tif self.datalen == 0 {{ return Vec::new(); }}").unwrap();
229-
writeln!(w, "\t\tlet ret = unsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }}.into();").unwrap();
229+
writeln!(w, "\t\tlet ret = unsafe {{ Box::from_raw(crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen)) }}.into();").unwrap();
230230
writeln!(w, "\t\tself.data = core::ptr::null_mut();").unwrap();
231231
writeln!(w, "\t\tself.datalen = 0;").unwrap();
232232
writeln!(w, "\t\tret").unwrap();
233233
writeln!(w, "\t}}").unwrap();
234234
writeln!(w, "\t#[allow(unused)] pub(crate) fn as_slice(&self) -> &[{}] {{", inner_type).unwrap();
235-
writeln!(w, "\t\tunsafe {{ core::slice::from_raw_parts_mut(self.data, self.datalen) }}").unwrap();
235+
writeln!(w, "\t\tunsafe {{ crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen) }}").unwrap();
236236
writeln!(w, "\t}}").unwrap();
237237
writeln!(w, "}}").unwrap();
238238

@@ -250,15 +250,15 @@ pub fn write_vec_block<W: std::io::Write>(w: &mut W, mangled_container: &str, in
250250
writeln!(w, "impl Drop for {} {{", mangled_container).unwrap();
251251
writeln!(w, "\tfn drop(&mut self) {{").unwrap();
252252
writeln!(w, "\t\tif self.datalen == 0 {{ return; }}").unwrap();
253-
writeln!(w, "\t\tlet _ = unsafe {{ Box::from_raw(core::slice::from_raw_parts_mut(self.data, self.datalen)) }};").unwrap();
253+
writeln!(w, "\t\tlet _ = unsafe {{ Box::from_raw(crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen)) }};").unwrap();
254254
writeln!(w, "\t}}").unwrap();
255255
writeln!(w, "}}").unwrap();
256256
if clonable {
257257
writeln!(w, "impl Clone for {} {{", mangled_container).unwrap();
258258
writeln!(w, "\tfn clone(&self) -> Self {{").unwrap();
259259
writeln!(w, "\t\tlet mut res = Vec::new();").unwrap();
260260
writeln!(w, "\t\tif self.datalen == 0 {{ return Self::from(res); }}").unwrap();
261-
writeln!(w, "\t\tres.extend_from_slice(unsafe {{ core::slice::from_raw_parts_mut(self.data, self.datalen) }});").unwrap();
261+
writeln!(w, "\t\tres.extend_from_slice(unsafe {{ crate::c_types::from_raw_parts_safer_mut(self.data, self.datalen) }});").unwrap();
262262
writeln!(w, "\t\tSelf::from(res)").unwrap();
263263
writeln!(w, "\t}}").unwrap();
264264
writeln!(w, "}}").unwrap();

lightning-c-bindings/src/c_types/mod.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ use alloc::{boxed::Box, vec::Vec, string::String};
3535

3636
use core::convert::TryFrom;
3737

38+
/// [`core::slice::from_raw_parts`] requires the pointer to be non-NULL even if the len is 0, which
39+
/// is annoying, so we wrap it here and fill in garbage in that case.
40+
pub(crate) unsafe fn from_raw_parts_safer_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
41+
if len == 0 {
42+
core::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), len)
43+
} else {
44+
assert!(data != core::ptr::null_mut());
45+
assert!(data != core::ptr::NonNull::dangling().as_ptr());
46+
core::slice::from_raw_parts_mut(data, len)
47+
}
48+
}
49+
50+
/// [`core::slice::from_raw_parts`] requires the pointer to be non-NULL even if the len is 0, which
51+
/// is annoying, so we wrap it here and fill in garbage in that case.
52+
pub(crate) unsafe fn from_raw_parts_safer<'a, T>(data: *const T, len: usize) -> &'a [T] {
53+
if len == 0 {
54+
core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), len)
55+
} else {
56+
assert!(data != core::ptr::null());
57+
assert!(data != core::ptr::NonNull::dangling().as_ptr());
58+
core::slice::from_raw_parts(data, len)
59+
}
60+
}
61+
3862
#[repr(C)]
3963
/// A dummy struct of which an instance must never exist.
4064
/// This corresponds to the Rust type `Infallible`, or, in unstable rust, `!`
@@ -575,7 +599,7 @@ impl Transaction {
575599
}
576600
pub(crate) fn into_bitcoin(&self) -> BitcoinTransaction {
577601
if self.datalen == 0 { panic!("0-length buffer can never represent a valid Transaction"); }
578-
::bitcoin::consensus::encode::deserialize(unsafe { core::slice::from_raw_parts(self.data, self.datalen) }).unwrap()
602+
::bitcoin::consensus::encode::deserialize(unsafe { from_raw_parts_safer(self.data, self.datalen) }).unwrap()
579603
}
580604
pub(crate) fn from_bitcoin(btc: &BitcoinTransaction) -> Self {
581605
let vec = ::bitcoin::consensus::encode::serialize(btc);
@@ -591,7 +615,7 @@ impl Drop for Transaction {
591615
}
592616
impl Clone for Transaction {
593617
fn clone(&self) -> Self {
594-
let sl = unsafe { core::slice::from_raw_parts(self.data, self.datalen) };
618+
let sl = unsafe { from_raw_parts_safer(self.data, self.datalen) };
595619
let mut v = Vec::new();
596620
v.extend_from_slice(&sl);
597621
Self::from_vec(v)
@@ -624,7 +648,7 @@ impl Witness {
624648
}
625649
}
626650
pub(crate) fn into_bitcoin(&self) -> BitcoinWitness {
627-
::bitcoin::consensus::encode::deserialize(unsafe { core::slice::from_raw_parts(self.data, self.datalen) }).unwrap()
651+
::bitcoin::consensus::encode::deserialize(unsafe { from_raw_parts_safer(self.data, self.datalen) }).unwrap()
628652
}
629653
pub(crate) fn from_bitcoin(btc: &BitcoinWitness) -> Self {
630654
let vec = ::bitcoin::consensus::encode::serialize(btc);
@@ -641,7 +665,7 @@ impl Drop for Witness {
641665
}
642666
impl Clone for Witness {
643667
fn clone(&self) -> Self {
644-
let sl = unsafe { core::slice::from_raw_parts(self.data, self.datalen) };
668+
let sl = unsafe { from_raw_parts_safer(self.data, self.datalen) };
645669
let mut v = Vec::new();
646670
v.extend_from_slice(&sl);
647671
Self::from_vec(v)
@@ -797,12 +821,7 @@ impl u8slice {
797821
}
798822
}
799823
pub(crate) fn to_slice(&self) -> &[u8] {
800-
if self.datalen == 0 { return &[]; }
801-
unsafe { core::slice::from_raw_parts(self.data, self.datalen) }
802-
}
803-
pub(crate) fn to_reader<'a>(&'a self) -> Cursor<&'a [u8]> {
804-
let sl = self.to_slice();
805-
Cursor::new(sl)
824+
unsafe { from_raw_parts_safer(self.data, self.datalen) }
806825
}
807826
pub(crate) fn from_vec(v: &derived::CVec_u8Z) -> u8slice {
808827
Self::from_slice(v.as_slice())
@@ -897,20 +916,20 @@ impl Into<Str> for &mut &str {
897916
impl Str {
898917
pub(crate) fn into_str(&self) -> &'static str {
899918
if self.len == 0 { return ""; }
900-
core::str::from_utf8(unsafe { core::slice::from_raw_parts(self.chars, self.len) }).unwrap()
919+
core::str::from_utf8(unsafe { from_raw_parts_safer(self.chars, self.len) }).unwrap()
901920
}
902921
pub(crate) fn into_string(mut self) -> String {
903922
let bytes = if self.len == 0 {
904923
Vec::new()
905924
} else if self.chars_is_owned {
906925
let ret = unsafe {
907-
Box::from_raw(core::slice::from_raw_parts_mut(unsafe { self.chars as *mut u8 }, self.len))
926+
Box::from_raw(from_raw_parts_safer_mut(unsafe { self.chars as *mut u8 }, self.len))
908927
}.into();
909928
self.chars_is_owned = false;
910929
ret
911930
} else {
912931
let mut ret = Vec::with_capacity(self.len);
913-
ret.extend_from_slice(unsafe { core::slice::from_raw_parts(self.chars, self.len) });
932+
ret.extend_from_slice(unsafe { from_raw_parts_safer(self.chars, self.len) });
914933
ret
915934
};
916935
String::from_utf8(bytes).unwrap()

0 commit comments

Comments
 (0)