diff --git a/src/lib.rs b/src/lib.rs index a6e03ab..242a290 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ pub mod native_cpuid { use core::cmp::min; use core::fmt; -use core::mem::transmute; +use core::mem::size_of; use core::slice; use core::str; @@ -115,6 +115,7 @@ pub struct CpuId { /// Low-level data-structure to store result of cpuid instruction. #[derive(Copy, Clone, Debug, Default)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] pub struct CpuIdResult { /// Return value EAX register pub eax: u32, @@ -563,6 +564,7 @@ impl CpuId { #[derive(Debug, Default)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] pub struct VendorInfo { ebx: u32, edx: u32, @@ -572,11 +574,14 @@ pub struct VendorInfo { impl VendorInfo { /// Return vendor identification as human readable string. pub fn as_string<'a>(&'a self) -> &'a str { + let brand_string_start = self as *const VendorInfo as *const u8; unsafe { - let brand_string_start = self as *const VendorInfo as *const u8; - let slice = slice::from_raw_parts(brand_string_start, 3 * 4); - let byte_array: &'a [u8] = transmute(slice); - str::from_utf8_unchecked(byte_array) + // Safety: VendorInfo is laid out with repr(C). + let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::()); + // Safety: The field is specified to be ASCII, and the only safe + // way to construct VendorInfo is from real CPUID data or the + // Default implementation. + str::from_utf8_unchecked(slice) } } } @@ -4005,19 +4010,21 @@ impl Iterator for SoCVendorAttributesIter { #[derive(Debug, Default)] #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(C)] pub struct SoCVendorBrand { - #[allow(dead_code)] data: [CpuIdResult; 3], } impl SoCVendorBrand { pub fn as_string<'a>(&'a self) -> &'a str { + let brand_string_start = self as *const SoCVendorBrand as *const u8; unsafe { - let brand_string_start = self as *const SoCVendorBrand as *const u8; - let slice = - slice::from_raw_parts(brand_string_start, core::mem::size_of::()); - let byte_array: &'a [u8] = transmute(slice); - str::from_utf8_unchecked(byte_array) + // Safety: SoCVendorBrand is laid out with repr(C). + let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::()); + // Safety: The field is specified to be ASCII, and the only safe + // way to construct SoCVendorBrand is from real CPUID data or the + // Default implementation. + str::from_utf8_unchecked(slice) } } } @@ -4130,18 +4137,18 @@ impl ExtendedFunctionInfo { /// Retrieve processor brand string. pub fn processor_brand_string<'a>(&'a self) -> Option<&'a str> { if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) { - Some(unsafe { - let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8; - let mut slice = slice::from_raw_parts(brand_string_start, 3 * 4 * 4); - - match slice.iter().position(|&x| x == 0) { - Some(index) => slice = slice::from_raw_parts(brand_string_start, index), - None => (), - } - - let byte_array: &'a [u8] = transmute(slice); - str::from_utf8_unchecked(byte_array) - }) + let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8; + // Safety: CpuIdResult is laid out with repr(C), and the array + // self.data contains 9 continguous elements. + let slice: &'a [u8] = unsafe { slice::from_raw_parts(brand_string_start, 3 * size_of::()) }; + + // Brand terminated at nul byte or end, whichever comes first. + let slice = slice.split(|&x| x == 0).next().unwrap(); + + // Safety: Field is specified to be ASCII, and the only safe way + // to construct ExtendedFunctionInfo is from real CPUID data + // or the Default implementation. + Some(unsafe { str::from_utf8_unchecked(slice) }) } else { None }