Skip to content

Commit 441d109

Browse files
authored
Merge pull request #42 from niklasf/fix-transmutes
Fix unsound transmutes (fixes #40)
2 parents 90a1a3b + bb8a79b commit 441d109

File tree

1 file changed

+30
-23
lines changed

1 file changed

+30
-23
lines changed

src/lib.rs

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub mod native_cpuid {
3838

3939
use core::cmp::min;
4040
use core::fmt;
41-
use core::mem::transmute;
41+
use core::mem::size_of;
4242
use core::slice;
4343
use core::str;
4444

@@ -115,6 +115,7 @@ pub struct CpuId {
115115
/// Low-level data-structure to store result of cpuid instruction.
116116
#[derive(Copy, Clone, Debug, Default)]
117117
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
118+
#[repr(C)]
118119
pub struct CpuIdResult {
119120
/// Return value EAX register
120121
pub eax: u32,
@@ -563,6 +564,7 @@ impl CpuId {
563564

564565
#[derive(Debug, Default)]
565566
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
567+
#[repr(C)]
566568
pub struct VendorInfo {
567569
ebx: u32,
568570
edx: u32,
@@ -572,11 +574,14 @@ pub struct VendorInfo {
572574
impl VendorInfo {
573575
/// Return vendor identification as human readable string.
574576
pub fn as_string<'a>(&'a self) -> &'a str {
577+
let brand_string_start = self as *const VendorInfo as *const u8;
575578
unsafe {
576-
let brand_string_start = self as *const VendorInfo as *const u8;
577-
let slice = slice::from_raw_parts(brand_string_start, 3 * 4);
578-
let byte_array: &'a [u8] = transmute(slice);
579-
str::from_utf8_unchecked(byte_array)
579+
// Safety: VendorInfo is laid out with repr(C).
580+
let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::<VendorInfo>());
581+
// Safety: The field is specified to be ASCII, and the only safe
582+
// way to construct VendorInfo is from real CPUID data or the
583+
// Default implementation.
584+
str::from_utf8_unchecked(slice)
580585
}
581586
}
582587
}
@@ -4005,19 +4010,21 @@ impl Iterator for SoCVendorAttributesIter {
40054010

40064011
#[derive(Debug, Default)]
40074012
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
4013+
#[repr(C)]
40084014
pub struct SoCVendorBrand {
4009-
#[allow(dead_code)]
40104015
data: [CpuIdResult; 3],
40114016
}
40124017

40134018
impl SoCVendorBrand {
40144019
pub fn as_string<'a>(&'a self) -> &'a str {
4020+
let brand_string_start = self as *const SoCVendorBrand as *const u8;
40154021
unsafe {
4016-
let brand_string_start = self as *const SoCVendorBrand as *const u8;
4017-
let slice =
4018-
slice::from_raw_parts(brand_string_start, core::mem::size_of::<SoCVendorBrand>());
4019-
let byte_array: &'a [u8] = transmute(slice);
4020-
str::from_utf8_unchecked(byte_array)
4022+
// Safety: SoCVendorBrand is laid out with repr(C).
4023+
let slice: &'a [u8] = slice::from_raw_parts(brand_string_start, size_of::<SoCVendorBrand>());
4024+
// Safety: The field is specified to be ASCII, and the only safe
4025+
// way to construct SoCVendorBrand is from real CPUID data or the
4026+
// Default implementation.
4027+
str::from_utf8_unchecked(slice)
40214028
}
40224029
}
40234030
}
@@ -4130,18 +4137,18 @@ impl ExtendedFunctionInfo {
41304137
/// Retrieve processor brand string.
41314138
pub fn processor_brand_string<'a>(&'a self) -> Option<&'a str> {
41324139
if self.leaf_is_supported(EAX_EXTENDED_BRAND_STRING) {
4133-
Some(unsafe {
4134-
let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8;
4135-
let mut slice = slice::from_raw_parts(brand_string_start, 3 * 4 * 4);
4136-
4137-
match slice.iter().position(|&x| x == 0) {
4138-
Some(index) => slice = slice::from_raw_parts(brand_string_start, index),
4139-
None => (),
4140-
}
4141-
4142-
let byte_array: &'a [u8] = transmute(slice);
4143-
str::from_utf8_unchecked(byte_array)
4144-
})
4140+
let brand_string_start = &self.data[2] as *const CpuIdResult as *const u8;
4141+
// Safety: CpuIdResult is laid out with repr(C), and the array
4142+
// self.data contains 9 continguous elements.
4143+
let slice: &'a [u8] = unsafe { slice::from_raw_parts(brand_string_start, 3 * size_of::<CpuIdResult>()) };
4144+
4145+
// Brand terminated at nul byte or end, whichever comes first.
4146+
let slice = slice.split(|&x| x == 0).next().unwrap();
4147+
4148+
// Safety: Field is specified to be ASCII, and the only safe way
4149+
// to construct ExtendedFunctionInfo is from real CPUID data
4150+
// or the Default implementation.
4151+
Some(unsafe { str::from_utf8_unchecked(slice) })
41454152
} else {
41464153
None
41474154
}

0 commit comments

Comments
 (0)