libfdt: Make ref casts & transmutes less unsafe
Use (safe) zerocopy::transmute! to transmute [u32; _] into [u8; _].
Implement FdtNodeMut::parent() with FdtNode::parent(), removing an
unsafe call to the C FFI fdt_parent_offset().
Give the compiler more information about Fdt::unchecked_from*_slice()
by casting the reference, instead of transmuting its bytes (which are
not the bytes of the type referred to!). The code remains unsafe
(because we're dereferencing a raw pointer) but is already more robust.
Rework the safety comments accordingly.
Clearly distinguish the fdt_property-to-FdtPropertyStruct ref cast from
the (*const)->& cast where the former is safe (thanks to 'transparent')
while the latter is only safe if we blindly trust C (this assumption
will be removed by a future patch).
Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I42785d2f5ae2dde2163d571869b36a480406cdd9
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 8a4e251..3248397 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -27,7 +27,6 @@
use core::cmp::max;
use core::ffi::{c_int, c_void, CStr};
use core::fmt;
-use core::mem;
use core::ops::Range;
use core::ptr;
use core::result;
@@ -201,6 +200,14 @@
#[derive(Debug)]
struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
+impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
+ fn as_ref(&self) -> &FdtPropertyStruct {
+ let ptr = self as *const _ as *const _;
+ // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
+ unsafe { &*ptr }
+ }
+}
+
impl FdtPropertyStruct {
fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
let mut len = 0;
@@ -212,7 +219,8 @@
return Err(FdtError::Internal); // shouldn't happen.
}
// SAFETY: prop is only returned when it points to valid libfdt_bindgen.
- Ok(unsafe { &*prop.cast::<FdtPropertyStruct>() })
+ let prop = unsafe { &*prop };
+ Ok(prop.as_ref())
}
fn name_offset(&self) -> c_int {
@@ -855,10 +863,7 @@
}
fn parent(&'a self) -> Result<FdtNode<'a>> {
- // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
- let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
-
- Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
+ self.as_node().parent()
}
/// Returns the compatible node of the given name that is next after this node.
@@ -979,22 +984,22 @@
///
/// # Safety
///
- /// The returned FDT might be invalid, only use on slices containing a valid DT.
+ /// It is undefined to call this function on a slice that does not contain a valid device tree.
pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
- // SAFETY: Fdt is a wrapper around a [u8], so the transmute is valid. The caller is
- // responsible for ensuring that it is actually a valid FDT.
- unsafe { mem::transmute::<&[u8], &Self>(fdt) }
+ let self_ptr = fdt as *const _ as *const _;
+ // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
+ unsafe { &*self_ptr }
}
/// Wraps a mutable slice containing a Flattened Device Tree.
///
/// # Safety
///
- /// The returned FDT might be invalid, only use on slices containing a valid DT.
+ /// It is undefined to call this function on a slice that does not contain a valid device tree.
pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
- // SAFETY: Fdt is a wrapper around a [u8], so the transmute is valid. The caller is
- // responsible for ensuring that it is actually a valid FDT.
- unsafe { mem::transmute::<&mut [u8], &mut Self>(fdt) }
+ let self_mut_ptr = fdt as *mut _ as *mut _;
+ // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
+ unsafe { &mut *self_mut_ptr }
}
/// Updates this FDT from a slice containing another FDT.