diff --git a/pinocchio/interface/src/state/account.rs b/pinocchio/interface/src/state/account.rs index 401e1c2d..853f0a8b 100644 --- a/pinocchio/interface/src/state/account.rs +++ b/pinocchio/interface/src/state/account.rs @@ -159,6 +159,8 @@ unsafe impl Transmutable for Account { const LEN: usize = core::mem::size_of::(); } +impl super::sealed::Sealed for Account {} + impl Initializable for Account { #[inline(always)] fn is_initialized(&self) -> Result { diff --git a/pinocchio/interface/src/state/mint.rs b/pinocchio/interface/src/state/mint.rs index 655173e6..ba72d09e 100644 --- a/pinocchio/interface/src/state/mint.rs +++ b/pinocchio/interface/src/state/mint.rs @@ -89,6 +89,8 @@ unsafe impl Transmutable for Mint { const LEN: usize = core::mem::size_of::(); } +impl super::sealed::Sealed for Mint {} + impl Initializable for Mint { #[inline(always)] fn is_initialized(&self) -> Result { diff --git a/pinocchio/interface/src/state/mod.rs b/pinocchio/interface/src/state/mod.rs index e9ed0a77..d04131d3 100644 --- a/pinocchio/interface/src/state/mod.rs +++ b/pinocchio/interface/src/state/mod.rs @@ -18,7 +18,7 @@ pub type COption = ([u8; 4], T); /// It is up to the type implementing this trait to guarantee that the cast is /// safe, i.e., the fields of the type are well aligned and there are no padding /// bytes. -pub unsafe trait Transmutable { +pub unsafe trait Transmutable: sealed::Sealed { /// The length of the type. /// /// This must be equal to the size of each individual field in the type. @@ -57,6 +57,13 @@ pub unsafe fn load(bytes: &[u8]) -> Result<&T, /// The caller must ensure that `bytes` contains a valid representation of `T`. #[inline(always)] pub unsafe fn load_unchecked(bytes: &[u8]) -> Result<&T, ProgramError> { + const { + assert!( + core::mem::align_of::() == 1, + " must have minimum alignment of 1" + ); + }; + if unlikely(bytes.len() != T::LEN) { return Err(ProgramError::InvalidAccountData); } @@ -93,8 +100,21 @@ pub unsafe fn load_mut( pub unsafe fn load_mut_unchecked( bytes: &mut [u8], ) -> Result<&mut T, ProgramError> { + const { + assert!( + core::mem::align_of::() == 1, + " must have minimum alignment of 1" + ); + }; + if unlikely(bytes.len() != T::LEN) { return Err(ProgramError::InvalidAccountData); } Ok(&mut *(bytes.as_mut_ptr() as *mut T)) } + +/// Private module to seal the `Transmutable` trait. +mod sealed { + /// Sealed trait to prevent external implementation of `Transmutable`. + pub trait Sealed {} +} diff --git a/pinocchio/interface/src/state/multisig.rs b/pinocchio/interface/src/state/multisig.rs index 7e453fd2..1adcb231 100644 --- a/pinocchio/interface/src/state/multisig.rs +++ b/pinocchio/interface/src/state/multisig.rs @@ -43,6 +43,8 @@ unsafe impl Transmutable for Multisig { const LEN: usize = core::mem::size_of::(); } +impl super::sealed::Sealed for Multisig {} + impl Initializable for Multisig { #[inline(always)] fn is_initialized(&self) -> Result {