From 0f02474d73205b23e446555d0bf1ee6118068f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Krasnoborski?= Date: Wed, 23 Mar 2022 20:08:17 +0100 Subject: [PATCH] Use casts instead of transmute MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit also replaces `.get_unchecked(0)` with `.as_ptr()` (when casting slice to typed object), which makes MIRI slightly happier (in previous approach, the pointer was valid only for the first byte) – in fact, it now passes tests with following flags: env MIRIFLAGS='-Zmiri-disable-alignment-check -Zmiri-disable-validation -Zmiri-tag-raw-pointers' \ cargo miri test --- src/abomonated.rs | 6 ++---- src/lib.rs | 15 +++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/abomonated.rs b/src/abomonated.rs index 328b195..079382b 100644 --- a/src/abomonated.rs +++ b/src/abomonated.rs @@ -1,5 +1,4 @@ -use std::mem::transmute; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; @@ -8,7 +7,7 @@ use super::{Abomonation, decode}; /// A type wrapping owned decoded abomonated data. /// /// This type ensures that decoding and pointer correction has already happened, -/// and implements `Deref` using a pointer cast (transmute). +/// and implements `Deref` using a pointer cast. /// /// #Safety /// @@ -121,7 +120,6 @@ impl> Deref for Abomonated { type Target = T; #[inline] fn deref(&self) -> &T { - let result: &T = unsafe { transmute(self.decoded.get_unchecked(0)) }; - result + unsafe { &*(self.decoded.as_ptr() as *const T) } } } diff --git a/src/lib.rs b/src/lib.rs index 016bcc8..61bd093 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,8 +72,7 @@ pub mod abomonated; /// #[inline] pub unsafe fn encode(typed: &T, write: &mut W) -> IOResult<()> { - let slice = std::slice::from_raw_parts(mem::transmute(typed), mem::size_of::()); - write.write_all(slice)?; + write.write_all(typed_to_bytes(typed))?; typed.entomb(write)?; Ok(()) } @@ -124,7 +123,7 @@ pub unsafe fn decode(bytes: &mut [u8]) -> Option<(&T, &mut [u8]) if bytes.len() < mem::size_of::() { None } else { let (split1, split2) = bytes.split_at_mut(mem::size_of::()); - let result: &mut T = mem::transmute(split1.get_unchecked_mut(0)); + let result: &mut T = &mut *(split1.as_mut_ptr() as *mut T); if let Some(remaining) = result.exhume(split2) { Some((result, remaining)) } @@ -468,7 +467,7 @@ impl Abomonation for String { if self.len() > bytes.len() { None } else { let (mine, rest) = bytes.split_at_mut(self.len()); - std::ptr::write(self, String::from_raw_parts(mem::transmute(mine.as_ptr()), self.len(), self.len())); + std::ptr::write(self, String::from_raw_parts(mine.as_mut_ptr(), self.len(), self.len())); Some(rest) } } @@ -514,7 +513,7 @@ impl Abomonation for Vec { impl Abomonation for Box { #[inline] unsafe fn entomb(&self, bytes: &mut W) -> IOResult<()> { - bytes.write_all(std::slice::from_raw_parts(mem::transmute(&**self), mem::size_of::()))?; + bytes.write_all(typed_to_bytes::(&**self))?; (**self).entomb(bytes)?; Ok(()) } @@ -524,7 +523,7 @@ impl Abomonation for Box { if binary_len > bytes.len() { None } else { let (mine, mut rest) = bytes.split_at_mut(binary_len); - std::ptr::write(self, mem::transmute(mine.as_mut_ptr() as *mut T)); + std::ptr::write(self, Box::from_raw(mine.as_mut_ptr() as *mut T)); let temp = rest; rest = (**self).exhume(temp)?; Some(rest) } @@ -535,8 +534,8 @@ impl Abomonation for Box { } // This method currently enables undefined behavior, by exposing padding bytes. -#[inline] unsafe fn typed_to_bytes(slice: &[T]) -> &[u8] { - std::slice::from_raw_parts(slice.as_ptr() as *const u8, slice.len() * mem::size_of::()) +#[inline] unsafe fn typed_to_bytes(typed: &T) -> &[u8] { + std::slice::from_raw_parts(typed as *const T as *const u8, mem::size_of_val(typed)) } mod network {