diff --git a/src/decoder.rs b/src/decoder.rs index 84d22d2..00b7620 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -1,5 +1,5 @@ use crate::*; -use core::{fmt, marker::PhantomData, mem::MaybeUninit, ops}; +use core::{fmt, hash, marker::PhantomData, mem, mem::MaybeUninit, ops}; /// Decodes raw instruction bytes into a machine-readable struct. #[derive(Clone, Debug)] @@ -266,10 +266,8 @@ pub type AllOperands = OperandArrayVec; /// Decode and store operands in a static array buffer. #[cfg(feature = "full-decoder")] -#[derive(Debug, Clone, Hash)] pub struct OperandArrayVec { - // TODO: use maybeuninit here - operands: [ffi::DecodedOperand; MAX_OPERANDS], + operands: [MaybeUninit; MAX_OPERANDS], num_initialized: usize, } @@ -280,35 +278,34 @@ impl Operands for OperandArrayVec { ctx: &ffi::DecoderContext, insn: &ffi::DecodedInstruction, ) -> Self { - use core::ptr; - let num_operands = match MAX_OPERANDS { MAX_OPERAND_COUNT => usize::from(insn.operand_count), MAX_OPERAND_COUNT_VISIBLE => usize::from(insn.operand_count_visible), _ => unreachable!(), }; - let mut ops = MaybeUninit::::uninit(); - let ops_ptr = ops.as_mut_ptr(); unsafe { - ptr::write(ptr::addr_of_mut!((*ops_ptr).num_initialized), num_operands); + let mut ops = OperandArrayVec { + num_initialized: num_operands, + operands: MaybeUninit::uninit().assume_init(), + }; ffi::ZydisDecoderDecodeOperands( decoder, ctx, insn, - ptr::addr_of_mut!((*ops_ptr).operands) as _, + ops.operands.as_mut_ptr() as _, MAX_OPERANDS as u8, ) .as_result() .expect("operand decoding should be infallible for valid arguments"); - ops.assume_init() + ops } } fn operands(&self) -> &[ffi::DecodedOperand] { - &self.operands[..self.num_initialized] + unsafe { mem::transmute(&self.operands[..self.num_initialized]) } } } @@ -321,3 +318,40 @@ impl PartialEq for OperandArrayVec { #[cfg(feature = "full-decoder")] impl Eq for OperandArrayVec {} + +#[cfg(feature = "full-decoder")] +impl hash::Hash for OperandArrayVec { + fn hash(&self, state: &mut H) { + self.operands().hash(state); + } +} + +#[cfg(feature = "full-decoder")] +impl Clone for OperandArrayVec { + fn clone(&self) -> Self { + unsafe { + let mut operands: [MaybeUninit; MAX_OPERANDS] = + MaybeUninit::uninit().assume_init(); + + std::ptr::copy_nonoverlapping( + self.operands.as_ptr(), + operands.as_mut_ptr(), + self.num_initialized, + ); + + Self { + num_initialized: self.num_initialized, + operands, + } + } + } +} + +#[cfg(feature = "full-decoder")] +impl fmt::Debug for OperandArrayVec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("OperandArrayVec") + .field(&self.operands()) + .finish() + } +}