Skip to content

Commit

Permalink
Merge pull request #42 from niklasf/fix-transmutes
Browse files Browse the repository at this point in the history
Fix unsound transmutes (fixes #40)
  • Loading branch information
gz authored Jan 20, 2021
2 parents 90a1a3b + bb8a79b commit 441d109
Showing 1 changed file with 30 additions and 23 deletions.
53 changes: 30 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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::<VendorInfo>());
// 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)
}
}
}
Expand Down Expand Up @@ -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::<SoCVendorBrand>());
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::<SoCVendorBrand>());
// 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)
}
}
}
Expand Down Expand Up @@ -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::<CpuIdResult>()) };

// 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
}
Expand Down

0 comments on commit 441d109

Please sign in to comment.