<commit_before>// This lint claims ugly casting is somehow safer than transmute, but there's
// no evidence that is the case. Shush.
#![allow(clippy::transmute_ptr_to_ptr)]

use std::fmt;
use std::mem::{self, MaybeUninit};

/// A wrapper around a byte buffer that is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the
/// buffer: a region at the beginning of the buffer that has been logically
/// filled with data, a region that has been initialized at some point but not
/// yet logically filled, and a region at the end that is fully uninitialized.
/// The filled region is guaranteed to be a  subset of the initialized region.
///
/// In summary, the contents of the buffer can be visualized as:
///
/// ```not_rust
/// [             capacity              ]
/// [ filled |         unfilled         ]
/// [    initialized    | uninitialized ]
/// ```
pub struct ReadBuf<'a> {
    buf: &'a mut [MaybeUninit<u8>],
    filled: usize,
    initialized: usize,
}

impl<'a> ReadBuf<'a> {
    /// Creates a new `ReadBuf` from a fully initialized buffer.
    #[inline]
    pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
        let initialized = buf.len();
        let buf = unsafe { mem::transmute::<&mut [u8], &mut [MaybeUninit<u8>]>(buf) };
        ReadBuf {
            buf,
            filled: 0,
            initialized,
        }
    }

    /// Creates a new `ReadBuf` from a fully uninitialized buffer.
    ///
    /// Use `assume_init` if part of the buffer is known to be already inintialized.
    #[inline]
    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
        ReadBuf {
            buf,
            filled: 0,
            initialized: 0,
        }
    }

    /// Returns the total capacity of the buffer.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.buf.len()
    }

    /// Returns a shared reference to the filled portion of the buffer.
    #[inline]
    pub fn filled(&self) -> &[u8] {
        let slice = &self.buf[..self.filled];
        // safety: filled describes how far into the buffer that the
        // user has filled with bytes, so it's been initialized.
        // TODO: This could use `MaybeUninit::slice_get_ref` when it is stable.
        unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(slice) }
    }

    /// Returns a mutable reference to the filled portion of the buffer.
    #[inline]
    pub fn filled_mut(&mut self) -> &mut [u8] {
        let slice = &mut self.buf[..self.filled];
        // safety: filled describes how far into the buffer that the
        // user has filled with bytes, so it's been initialized.
        // TODO: This could use `MaybeUninit::slice_get_mut` when it is stable.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns a new `ReadBuf` comprised of the unfilled section up to `n`.
    #[inline]
    pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
        let max = std::cmp::min(self.remaining(), n);
        // Saftey: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`.
        unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) }
    }

    /// Returns a shared reference to the initialized portion of the buffer.
    ///
    /// This includes the filled portion.
    #[inline]
    pub fn initialized(&self) -> &[u8] {
        let slice = &self.buf[..self.initialized];
        // safety: initialized describes how far into the buffer that the
        // user has at some point initialized with bytes.
        // TODO: This could use `MaybeUninit::slice_get_ref` when it is stable.
        unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(slice) }
    }

    /// Returns a mutable reference to the initialized portion of the buffer.
    ///
    /// This includes the filled portion.
    #[inline]
    pub fn initialized_mut(&mut self) -> &mut [u8] {
        let slice = &mut self.buf[..self.initialized];
        // safety: initialized describes how far into the buffer that the
        // user has at some point initialized with bytes.
        // TODO: This could use `MaybeUninit::slice_get_mut` when it is stable.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
    /// initialized.
    ///
    /// # Safety
    ///
    /// The caller must not de-initialize portions of the buffer that have already been initialized.
    #[inline]
    pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        &mut self.buf[self.filled..]
    }

    /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
    ///
    /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
    /// the first use.
    #[inline]
    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
        self.initialize_unfilled_to(self.remaining())
    }

    /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
    /// fully initialized.
    ///
    /// # Panics
    ///
    /// Panics if `self.remaining()` is less than `n`.
    #[inline]
    pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
        assert!(self.remaining() >= n, "n overflows remaining");

        // This can't overflow, otherwise the assert above would have failed.
        let end = self.filled + n;

        if self.initialized < end {
            unsafe {
                self.buf[self.initialized..end]
                    .as_mut_ptr()
                    .write_bytes(0, end - self.initialized);
            }
            self.initialized = end;
        }

        let slice = &mut self.buf[self.filled..end];
        // safety: just above, we checked that the end of the buf has
        // been initialized to some value.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns the number of bytes at the end of the slice that have not yet been filled.
    #[inline]
    pub fn remaining(&self) -> usize {
        self.capacity() - self.filled
    }

    /// Clears the buffer, resetting the filled region to empty.
    ///
    /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
    #[inline]
    pub fn clear(&mut self) {
        self.filled = 0;
    }

    /// Advances the size of the filled region of the buffer.
    ///
    /// The number of initialized bytes is not changed.
    ///
    /// # Panics
    ///
    /// Panics if the filled region of the buffer would become larger than the initialized region.
    #[inline]
    pub fn advance(&mut self, n: usize) {
        let new = self.filled.checked_add(n).expect("filled overflow");
        self.set_filled(new);
    }

    /// Sets the size of the filled region of the buffer.
    ///
    /// The number of initialized bytes is not changed.
    ///
    /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
    /// example, by a `AsyncRead` implementation that compresses data in-place).
    ///
    /// # Panics
    ///
    /// Panics if the filled region of the buffer would become larger than the intialized region.
    #[inline]
    pub fn set_filled(&mut self, n: usize) {
        assert!(
            n <= self.initialized,
            "filled must not become larger than initialized"
        );
        self.filled = n;
    }

    /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
    ///
    /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
    /// bytes than are already known to be initialized.
    ///
    /// # Safety
    ///
    /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized.
    #[inline]
    pub unsafe fn assume_init(&mut self, n: usize) {
        let new = self.filled + n;
        if new > self.initialized {
            self.initialized = new;
        }
    }

    /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
    ///
    /// # Panics
    ///
    /// Panics if `self.remaining()` is less than `buf.len()`.
    #[inline]
    pub fn put_slice(&mut self, buf: &[u8]) {
        assert!(
            self.remaining() >= buf.len(),
            "buf.len() must fit in remaining()"
        );

        let amt = buf.len();
        // Cannot overflow, asserted above
        let end = self.filled + amt;

        // Safety: the length is asserted above
        unsafe {
            self.buf[self.filled..end]
                .as_mut_ptr()
                .cast::<u8>()
                .copy_from_nonoverlapping(buf.as_ptr(), amt);
        }

        if self.initialized < end {
            self.initialized = end;
        }
        self.filled = end;
    }
}

impl fmt::Debug for ReadBuf<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ReadBuf")
            .field("filled", &self.filled)
            .field("initialized", &self.initialized)
            .field("capacity", &self.capacity())
            .finish()
    }
}
<commit_msg>io: expand on de-initialization of ReadBuf (#3035)<commit_after>// This lint claims ugly casting is somehow safer than transmute, but there's
// no evidence that is the case. Shush.
#![allow(clippy::transmute_ptr_to_ptr)]

use std::fmt;
use std::mem::{self, MaybeUninit};

/// A wrapper around a byte buffer that is incrementally filled and initialized.
///
/// This type is a sort of "double cursor". It tracks three regions in the
/// buffer: a region at the beginning of the buffer that has been logically
/// filled with data, a region that has been initialized at some point but not
/// yet logically filled, and a region at the end that may be uninitialized.
/// The filled region is guaranteed to be a subset of the initialized region.
///
/// In summary, the contents of the buffer can be visualized as:
///
/// ```not_rust
/// [             capacity              ]
/// [ filled |         unfilled         ]
/// [    initialized    | uninitialized ]
/// ```
///
/// It is undefined behavior to de-initialize any bytes from the uninitialized
/// region, since it is merely unknown whether this region is uninitialized or
/// not, and if part of it turns out to be initialized, it must stay initialized.
pub struct ReadBuf<'a> {
    buf: &'a mut [MaybeUninit<u8>],
    filled: usize,
    initialized: usize,
}

impl<'a> ReadBuf<'a> {
    /// Creates a new `ReadBuf` from a fully initialized buffer.
    #[inline]
    pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> {
        let initialized = buf.len();
        let buf = unsafe { mem::transmute::<&mut [u8], &mut [MaybeUninit<u8>]>(buf) };
        ReadBuf {
            buf,
            filled: 0,
            initialized,
        }
    }

    /// Creates a new `ReadBuf` from a fully uninitialized buffer.
    ///
    /// Use `assume_init` if part of the buffer is known to be already inintialized.
    #[inline]
    pub fn uninit(buf: &'a mut [MaybeUninit<u8>]) -> ReadBuf<'a> {
        ReadBuf {
            buf,
            filled: 0,
            initialized: 0,
        }
    }

    /// Returns the total capacity of the buffer.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.buf.len()
    }

    /// Returns a shared reference to the filled portion of the buffer.
    #[inline]
    pub fn filled(&self) -> &[u8] {
        let slice = &self.buf[..self.filled];
        // safety: filled describes how far into the buffer that the
        // user has filled with bytes, so it's been initialized.
        // TODO: This could use `MaybeUninit::slice_get_ref` when it is stable.
        unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(slice) }
    }

    /// Returns a mutable reference to the filled portion of the buffer.
    #[inline]
    pub fn filled_mut(&mut self) -> &mut [u8] {
        let slice = &mut self.buf[..self.filled];
        // safety: filled describes how far into the buffer that the
        // user has filled with bytes, so it's been initialized.
        // TODO: This could use `MaybeUninit::slice_get_mut` when it is stable.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns a new `ReadBuf` comprised of the unfilled section up to `n`.
    #[inline]
    pub fn take(&mut self, n: usize) -> ReadBuf<'_> {
        let max = std::cmp::min(self.remaining(), n);
        // Saftey: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`.
        unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) }
    }

    /// Returns a shared reference to the initialized portion of the buffer.
    ///
    /// This includes the filled portion.
    #[inline]
    pub fn initialized(&self) -> &[u8] {
        let slice = &self.buf[..self.initialized];
        // safety: initialized describes how far into the buffer that the
        // user has at some point initialized with bytes.
        // TODO: This could use `MaybeUninit::slice_get_ref` when it is stable.
        unsafe { mem::transmute::<&[MaybeUninit<u8>], &[u8]>(slice) }
    }

    /// Returns a mutable reference to the initialized portion of the buffer.
    ///
    /// This includes the filled portion.
    #[inline]
    pub fn initialized_mut(&mut self) -> &mut [u8] {
        let slice = &mut self.buf[..self.initialized];
        // safety: initialized describes how far into the buffer that the
        // user has at some point initialized with bytes.
        // TODO: This could use `MaybeUninit::slice_get_mut` when it is stable.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully
    /// initialized.
    ///
    /// # Safety
    ///
    /// The caller must not de-initialize portions of the buffer that have already been initialized.
    /// This includes any bytes in the region marked as uninitialized by `ReadBuf`.
    #[inline]
    pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit<u8>] {
        &mut self.buf[self.filled..]
    }

    /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
    ///
    /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after
    /// the first use.
    #[inline]
    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
        self.initialize_unfilled_to(self.remaining())
    }

    /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
    /// fully initialized.
    ///
    /// # Panics
    ///
    /// Panics if `self.remaining()` is less than `n`.
    #[inline]
    pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
        assert!(self.remaining() >= n, "n overflows remaining");

        // This can't overflow, otherwise the assert above would have failed.
        let end = self.filled + n;

        if self.initialized < end {
            unsafe {
                self.buf[self.initialized..end]
                    .as_mut_ptr()
                    .write_bytes(0, end - self.initialized);
            }
            self.initialized = end;
        }

        let slice = &mut self.buf[self.filled..end];
        // safety: just above, we checked that the end of the buf has
        // been initialized to some value.
        unsafe { mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(slice) }
    }

    /// Returns the number of bytes at the end of the slice that have not yet been filled.
    #[inline]
    pub fn remaining(&self) -> usize {
        self.capacity() - self.filled
    }

    /// Clears the buffer, resetting the filled region to empty.
    ///
    /// The number of initialized bytes is not changed, and the contents of the buffer are not modified.
    #[inline]
    pub fn clear(&mut self) {
        self.filled = 0;
    }

    /// Advances the size of the filled region of the buffer.
    ///
    /// The number of initialized bytes is not changed.
    ///
    /// # Panics
    ///
    /// Panics if the filled region of the buffer would become larger than the initialized region.
    #[inline]
    pub fn advance(&mut self, n: usize) {
        let new = self.filled.checked_add(n).expect("filled overflow");
        self.set_filled(new);
    }

    /// Sets the size of the filled region of the buffer.
    ///
    /// The number of initialized bytes is not changed.
    ///
    /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for
    /// example, by a `AsyncRead` implementation that compresses data in-place).
    ///
    /// # Panics
    ///
    /// Panics if the filled region of the buffer would become larger than the intialized region.
    #[inline]
    pub fn set_filled(&mut self, n: usize) {
        assert!(
            n <= self.initialized,
            "filled must not become larger than initialized"
        );
        self.filled = n;
    }

    /// Asserts that the first `n` unfilled bytes of the buffer are initialized.
    ///
    /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer
    /// bytes than are already known to be initialized.
    ///
    /// # Safety
    ///
    /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized.
    #[inline]
    pub unsafe fn assume_init(&mut self, n: usize) {
        let new = self.filled + n;
        if new > self.initialized {
            self.initialized = new;
        }
    }

    /// Appends data to the buffer, advancing the written position and possibly also the initialized position.
    ///
    /// # Panics
    ///
    /// Panics if `self.remaining()` is less than `buf.len()`.
    #[inline]
    pub fn put_slice(&mut self, buf: &[u8]) {
        assert!(
            self.remaining() >= buf.len(),
            "buf.len() must fit in remaining()"
        );

        let amt = buf.len();
        // Cannot overflow, asserted above
        let end = self.filled + amt;

        // Safety: the length is asserted above
        unsafe {
            self.buf[self.filled..end]
                .as_mut_ptr()
                .cast::<u8>()
                .copy_from_nonoverlapping(buf.as_ptr(), amt);
        }

        if self.initialized < end {
            self.initialized = end;
        }
        self.filled = end;
    }
}

impl fmt::Debug for ReadBuf<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("ReadBuf")
            .field("filled", &self.filled)
            .field("initialized", &self.initialized)
            .field("capacity", &self.capacity())
            .finish()
    }
}
<|endoftext|>


<commit_before>use super::errors::{TransferInvalid as Invalid, TransferValidationError as Error};
use bls::get_withdrawal_credentials;
use tree_hash::SignedRoot;
use types::*;

/// Indicates if a `Transfer` is valid to be included in a block in the current epoch of the given
/// state.
///
/// Returns `Ok(())` if the `Transfer` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.6.3
pub fn verify_transfer<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify_transfer_parametric(state, transfer, spec, false)
}

/// Like `verify_transfer` but doesn't run checks which may become true in future states.
///
/// Spec v0.6.3
pub fn verify_transfer_time_independent_only<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify_transfer_parametric(state, transfer, spec, true)
}

/// Parametric version of `verify_transfer` that allows some checks to be skipped.
///
/// When `time_independent_only == true`, time-specific parameters are ignored, including:
///
/// - Balance considerations (e.g., adequate balance, not dust, etc).
/// - `transfer.slot` does not have to exactly match `state.slot`, it just needs to be in the
///     present or future.
/// - Validator transfer eligibility (e.g., is withdrawable)
///
/// Spec v0.6.3
fn verify_transfer_parametric<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
    time_independent_only: bool,
) -> Result<(), Error> {
    let sender_balance = *state
        .balances
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;

    let recipient_balance = *state
        .balances
        .get(transfer.recipient as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.recipient)))?;

    // Safely determine `amount + fee`.
    let total_amount = transfer
        .amount
        .checked_add(transfer.fee)
        .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;

    // Verify the sender has adequate balance.
    verify!(
        time_independent_only || sender_balance >= transfer.amount,
        Invalid::FromBalanceInsufficient(transfer.amount, sender_balance)
    );

    // Verify sender balance will not be "dust" (i.e., greater than zero but less than the minimum deposit
    // amount).
    verify!(
        time_independent_only
            || (sender_balance == total_amount)
            || (sender_balance >= (total_amount + spec.min_deposit_amount)),
        Invalid::SenderDust(sender_balance - total_amount, spec.min_deposit_amount)
    );

    // Verify the recipient balance will not be dust.
    verify!(
        time_independent_only || ((recipient_balance + transfer.amount) >= spec.min_deposit_amount),
        Invalid::RecipientDust(sender_balance - total_amount, spec.min_deposit_amount)
    );

    // If loosely enforcing `transfer.slot`, ensure the slot is not in the past. Otherwise, ensure
    // the transfer slot equals the state slot.
    if time_independent_only {
        verify!(
            state.slot <= transfer.slot,
            Invalid::TransferSlotInPast(state.slot, transfer.slot)
        );
    } else {
        verify!(
            state.slot == transfer.slot,
            Invalid::StateSlotMismatch(state.slot, transfer.slot)
        );
    }

    // Load the sender `Validator` record from the state.
    let sender_validator = state
        .validator_registry
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;

    let epoch = state.slot.epoch(T::slots_per_epoch());

    // Ensure one of the following is met:
    //
    // - Time dependent checks are being ignored.
    // - The sender has not been activated.
    // - The sender is withdrawable at the state's epoch.
    // - The transfer will not reduce the sender below the max effective balance.
    verify!(
        time_independent_only
            || sender_validator.activation_eligibility_epoch == spec.far_future_epoch
            || sender_validator.is_withdrawable_at(epoch)
            || total_amount + spec.max_effective_balance <= sender_balance,
        Invalid::FromValidatorIneligibleForTransfer(transfer.sender)
    );

    // Ensure the withdrawal credentials generated from the sender's pubkey match those stored in
    // the validator registry.
    //
    // This ensures the validator can only perform a transfer when they are in control of the
    // withdrawal address.
    let transfer_withdrawal_credentials = Hash256::from_slice(
        &get_withdrawal_credentials(&transfer.pubkey, spec.bls_withdrawal_prefix_byte)[..],
    );
    verify!(
        sender_validator.withdrawal_credentials == transfer_withdrawal_credentials,
        Invalid::WithdrawalCredentialsMismatch(
            sender_validator.withdrawal_credentials,
            transfer_withdrawal_credentials
        )
    );

    // Verify the transfer signature.
    let message = transfer.signed_root();
    let domain = spec.get_domain(
        transfer.slot.epoch(T::slots_per_epoch()),
        Domain::Transfer,
        &state.fork,
    );
    verify!(
        transfer
            .signature
            .verify(&message[..], domain, &transfer.pubkey),
        Invalid::BadSignature
    );

    Ok(())
}

/// Executes a transfer on the state.
///
/// Does not check that the transfer is valid, however checks for overflow in all actions.
///
/// Spec v0.6.3
pub fn execute_transfer<T: EthSpec>(
    state: &mut BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let sender_balance = *state
        .balances
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;
    let recipient_balance = *state
        .balances
        .get(transfer.recipient as usize)
        .ok_or_else(|| Error::Invalid(Invalid::ToValidatorUnknown(transfer.recipient)))?;

    let proposer_index =
        state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec)?;
    let proposer_balance = state.balances[proposer_index];

    let total_amount = transfer
        .amount
        .checked_add(transfer.fee)
        .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;

    state.balances[transfer.sender as usize] =
        sender_balance.checked_sub(total_amount).ok_or_else(|| {
            Error::Invalid(Invalid::FromBalanceInsufficient(
                total_amount,
                sender_balance,
            ))
        })?;

    state.balances[transfer.recipient as usize] = recipient_balance
        .checked_add(transfer.amount)
        .ok_or_else(|| {
            Error::Invalid(Invalid::ToBalanceOverflow(
                recipient_balance,
                transfer.amount,
            ))
        })?;

    state.balances[proposer_index] =
        proposer_balance.checked_add(transfer.fee).ok_or_else(|| {
            Error::Invalid(Invalid::ProposerBalanceOverflow(
                proposer_balance,
                transfer.fee,
            ))
        })?;

    Ok(())
}
<commit_msg>Verify transfer now checks for amount + fees. (#457)<commit_after>use super::errors::{TransferInvalid as Invalid, TransferValidationError as Error};
use bls::get_withdrawal_credentials;
use tree_hash::SignedRoot;
use types::*;

/// Indicates if a `Transfer` is valid to be included in a block in the current epoch of the given
/// state.
///
/// Returns `Ok(())` if the `Transfer` is valid, otherwise indicates the reason for invalidity.
///
/// Spec v0.6.3
pub fn verify_transfer<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify_transfer_parametric(state, transfer, spec, false)
}

/// Like `verify_transfer` but doesn't run checks which may become true in future states.
///
/// Spec v0.6.3
pub fn verify_transfer_time_independent_only<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    verify_transfer_parametric(state, transfer, spec, true)
}

/// Parametric version of `verify_transfer` that allows some checks to be skipped.
///
/// When `time_independent_only == true`, time-specific parameters are ignored, including:
///
/// - Balance considerations (e.g., adequate balance, not dust, etc).
/// - `transfer.slot` does not have to exactly match `state.slot`, it just needs to be in the
///     present or future.
/// - Validator transfer eligibility (e.g., is withdrawable)
///
/// Spec v0.6.3
fn verify_transfer_parametric<T: EthSpec>(
    state: &BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
    time_independent_only: bool,
) -> Result<(), Error> {
    let sender_balance = *state
        .balances
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;

    let recipient_balance = *state
        .balances
        .get(transfer.recipient as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.recipient)))?;

    // Safely determine `amount + fee`.
    let total_amount = transfer
        .amount
        .checked_add(transfer.fee)
        .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;

    // Verify the sender has adequate balance.
    verify!(
        time_independent_only || sender_balance >= total_amount,
        Invalid::FromBalanceInsufficient(total_amount, sender_balance)
    );

    // Verify sender balance will not be "dust" (i.e., greater than zero but less than the minimum deposit
    // amount).
    verify!(
        time_independent_only
            || (sender_balance == total_amount)
            || (sender_balance >= (total_amount + spec.min_deposit_amount)),
        Invalid::SenderDust(sender_balance - total_amount, spec.min_deposit_amount)
    );

    // Verify the recipient balance will not be dust.
    verify!(
        time_independent_only || ((recipient_balance + transfer.amount) >= spec.min_deposit_amount),
        Invalid::RecipientDust(sender_balance - total_amount, spec.min_deposit_amount)
    );

    // If loosely enforcing `transfer.slot`, ensure the slot is not in the past. Otherwise, ensure
    // the transfer slot equals the state slot.
    if time_independent_only {
        verify!(
            state.slot <= transfer.slot,
            Invalid::TransferSlotInPast(state.slot, transfer.slot)
        );
    } else {
        verify!(
            state.slot == transfer.slot,
            Invalid::StateSlotMismatch(state.slot, transfer.slot)
        );
    }

    // Load the sender `Validator` record from the state.
    let sender_validator = state
        .validator_registry
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;

    let epoch = state.slot.epoch(T::slots_per_epoch());

    // Ensure one of the following is met:
    //
    // - Time dependent checks are being ignored.
    // - The sender has not been activated.
    // - The sender is withdrawable at the state's epoch.
    // - The transfer will not reduce the sender below the max effective balance.
    verify!(
        time_independent_only
            || sender_validator.activation_eligibility_epoch == spec.far_future_epoch
            || sender_validator.is_withdrawable_at(epoch)
            || total_amount + spec.max_effective_balance <= sender_balance,
        Invalid::FromValidatorIneligibleForTransfer(transfer.sender)
    );

    // Ensure the withdrawal credentials generated from the sender's pubkey match those stored in
    // the validator registry.
    //
    // This ensures the validator can only perform a transfer when they are in control of the
    // withdrawal address.
    let transfer_withdrawal_credentials = Hash256::from_slice(
        &get_withdrawal_credentials(&transfer.pubkey, spec.bls_withdrawal_prefix_byte)[..],
    );
    verify!(
        sender_validator.withdrawal_credentials == transfer_withdrawal_credentials,
        Invalid::WithdrawalCredentialsMismatch(
            sender_validator.withdrawal_credentials,
            transfer_withdrawal_credentials
        )
    );

    // Verify the transfer signature.
    let message = transfer.signed_root();
    let domain = spec.get_domain(
        transfer.slot.epoch(T::slots_per_epoch()),
        Domain::Transfer,
        &state.fork,
    );
    verify!(
        transfer
            .signature
            .verify(&message[..], domain, &transfer.pubkey),
        Invalid::BadSignature
    );

    Ok(())
}

/// Executes a transfer on the state.
///
/// Does not check that the transfer is valid, however checks for overflow in all actions.
///
/// Spec v0.6.3
pub fn execute_transfer<T: EthSpec>(
    state: &mut BeaconState<T>,
    transfer: &Transfer,
    spec: &ChainSpec,
) -> Result<(), Error> {
    let sender_balance = *state
        .balances
        .get(transfer.sender as usize)
        .ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.sender)))?;
    let recipient_balance = *state
        .balances
        .get(transfer.recipient as usize)
        .ok_or_else(|| Error::Invalid(Invalid::ToValidatorUnknown(transfer.recipient)))?;

    let proposer_index =
        state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec)?;
    let proposer_balance = state.balances[proposer_index];

    let total_amount = transfer
        .amount
        .checked_add(transfer.fee)
        .ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;

    state.balances[transfer.sender as usize] =
        sender_balance.checked_sub(total_amount).ok_or_else(|| {
            Error::Invalid(Invalid::FromBalanceInsufficient(
                total_amount,
                sender_balance,
            ))
        })?;

    state.balances[transfer.recipient as usize] = recipient_balance
        .checked_add(transfer.amount)
        .ok_or_else(|| {
            Error::Invalid(Invalid::ToBalanceOverflow(
                recipient_balance,
                transfer.amount,
            ))
        })?;

    state.balances[proposer_index] =
        proposer_balance.checked_add(transfer.fee).ok_or_else(|| {
            Error::Invalid(Invalid::ProposerBalanceOverflow(
                proposer_balance,
                transfer.fee,
            ))
        })?;

    Ok(())
}
<|endoftext|>


<commit_before>//! Test Driven Learning Project.
//! Desenvolva TDD e programação com TDD e programação!
//! Módulo novice.
//!
//! The MIT License (MIT)
//!
//! Copyright (c) 2016 Paulo Henrique Rodrigues Pinheiro <paulo@sysincloud.it>
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.

use std::collections::HashSet;

/// A função `negue` deve receber um valor boleano (verdadeiro ou falso) e
/// retornar a negação desse valor.
///
/// # Examples
///
/// ```
/// extern crate rust;
/// assert_eq!(true, rust::problems::negue(false));
/// assert_eq!(false, rust::problems::negue(true));
/// ```
pub fn negue(value:bool) -> bool {
    !value
}

/// A função `diga_ola` deve ser escrita de tal forma que receba como
/// parâmetro um argumento *string*. Deve retornar a *string* "Olá, ", seguida
/// do argumento recebido, mais um ponto final. A *string* recebida deve estar
/// limpa, ou seja, sem caracteres de espaço no começo ou no fim. Se a *string*
/// estiver vazia, retorna apenas "Olá!"
///
/// # Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!("Olá!", rust::problems::diga_ola(""));
/// assert_eq!("Olá!", rust::problems::diga_ola("    "));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("Paulo"));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("  Paulo  "));
/// assert_eq!("Olá, Paulo Henrique.", rust::problems::diga_ola("  Paulo Henrique  "));
/// ```
pub fn diga_ola(nome:&str) -> String {
    let nome_limpo = nome.trim();

    if nome_limpo.is_empty() {
        return "Olá!".to_string();
    }

    "Olá, ".to_string() + &nome_limpo.to_string() + "."
}

/// A função `lista_numeros_pares` deve receber um parâmetro numérico
/// inteiro que determina quantos números pares devem estar em um array que
/// será o retorno da função.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_numeros_pares(0).len());
/// assert_eq!(vec![2], rust::problems::lista_numeros_pares(1));
/// assert_eq!(vec![2, 4, 6, 8], rust::problems::lista_numeros_pares(4));
/// assert_eq!(vec![2, 4, 6, 8, 10], rust::problems::lista_numeros_pares(5));
/// assert_eq!(0, rust::problems::lista_numeros_pares(-1).len());
/// ```
pub fn lista_numeros_pares(quantos:i32) -> Vec<i32> {
    (1..quantos+1).map(|x| x*2).collect::<Vec<i32>>()
}

/// A função `lista_multiplos` deve receber dois parâmetros numéricos
/// inteiros e retornar uma lista de números inteiros. O tamanho da lista é
/// determinado pelo primeiro parâmetro, e o número base será o segundo
/// parâmetro.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_multiplos(0, 10).len());
/// assert_eq!(0, rust::problems::lista_multiplos(-1, 10).len());
/// assert_eq!(vec![-3, -2, -1], rust::problems::lista_multiplos(3, -1));
/// assert_eq!(0, rust::problems::lista_multiplos(3, 0).len());
/// assert_eq!(vec![10, 20, 30], rust::problems::lista_multiplos(3, 10));
/// ```
pub fn lista_multiplos(quantos:i32, base:i32) -> Vec<i32> {
    if base == 0 {
        return vec![];
    }

    let mut response = (1..quantos+1).map(|x| x*base).collect::<Vec<i32>>();

    if base < 1 {
        response.reverse();
    }

    response
}

/// A função `soma` deve receber um *array* de números inteiros, e retornar
/// a sua soma. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::soma(vec![]));
/// assert_eq!(1, rust::problems::soma(vec![1]));
/// assert_eq!(3, rust::problems::soma(vec![1, 2]));
/// ```
pub fn soma(lista:Vec<i32>) -> i32 {
    lista.iter().fold(0, |result, x| result + x)
}

/// A função `subtracao` deve receber um *array* de números inteiros, e
/// retornar a subtração de todos os elementos em sequência. Por exemplo,
/// subtracao([3,2,1]) deve retornar 0, e subtracao([10,2,3]) deve retornar 5.
/// Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::subtracao(vec![3, 2, 1]));
/// assert_eq!(5, rust::problems::subtracao(vec![10, 2, 3]));
/// assert_eq!(0, rust::problems::subtracao(vec![]));
/// assert_eq!(-1, rust::problems::subtracao(vec![1, 2]));
/// assert_eq!(4, rust::problems::subtracao(vec![-1, -2, -3]));
/// assert_eq!(3, rust::problems::subtracao(vec![9, 3, 2, 1]));
/// ```
pub fn subtracao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result - x)
}

/// A função `multiplicação` deve receber um *array* de números inteiros, e
/// retornar o seu produto. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(6, rust::problems::multiplicacao(vec![1, 2, 3]));
/// assert_eq!(0, rust::problems::multiplicacao(vec![]));
/// assert_eq!(-8, rust::problems::multiplicacao(vec![-2, 1, 4]));
/// assert_eq!(8, rust::problems::multiplicacao(vec![-2, -1, 4]));
pub fn multiplicacao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista.iter().fold(1, |result, x| result * x)
}

/// A função `divisao` deve receber um *array* de números inteiros, e
/// retornar o resultado da sequência de divisões por cada elemento. Por
/// exemplo, divisão([16, 4, 2]) deve retornar 2, e divisão([100,2,10]) deve
/// retornar 5. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(2, rust::problems::divisao(vec![5, 2]));
/// assert_eq!(0, rust::problems::divisao(vec![]));
/// assert_eq!(0, rust::problems::divisao(vec![0]));
/// assert_eq!(2, rust::problems::divisao(vec![16, 4, 2]));
/// assert_eq!(5, rust::problems::divisao(vec![100, 2, 10]));
/// assert_eq!(0, rust::problems::divisao(vec![0, 1]));
/// //assert_eq!(0, rust::problems::divisao(vec![1, 0]));
pub fn divisao(lista:Vec<i32>) ->i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result / x)
}

/// A função `maior` deve receber um *array* de números inteiros e retornar
/// qual é o maior deles.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(100, rust::problems::maior(vec![0, 1 ,100]));
/// assert_eq!(0, rust::problems::maior(vec![0]));
pub fn maior(lista:Vec<i32>)-> i32 {
    lista.iter().fold(lista[0], |result, x| if *x > result {*x} else {result})
}

/// A função `intersecao` deve receber dois *arrays* contendo números
/// inteiros, e retornar a interseção entre os conjuntos, ou seja, um *array*
/// que contenha apenas os números que estejam contidos nos dois *arrays*
/// passados para a função.
///
/// Examples
///
/// ```
/// assert_eq!(0, rust::problems::intersecao(vec![], vec![]).len());
/// assert_eq!(0, rust::problems::intersecao(vec![1, 2], vec![3, 4]).len());
/// assert_eq!(vec![2], rust::problems::intersecao(vec![1, 2], vec![2, 3]));
pub fn intersecao(a:Vec<i32>, b:Vec<i32>) -> Vec<i32> {
    let _a:HashSet<i32> = a.iter().cloned().collect();
    let _b:HashSet<i32> = b.iter().cloned().collect();

    _a.intersection(&_b).cloned().collect::<Vec<i32>>()
}
<commit_msg>Utiliza a macro format para não ficar criando Strings e concatenando<commit_after>//! Test Driven Learning Project.
//! Desenvolva TDD e programação com TDD e programação!
//! Módulo novice.
//!
//! The MIT License (MIT)
//!
//! Copyright (c) 2016 Paulo Henrique Rodrigues Pinheiro <paulo@sysincloud.it>
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.

use std::collections::HashSet;

/// A função `negue` deve receber um valor boleano (verdadeiro ou falso) e
/// retornar a negação desse valor.
///
/// # Examples
///
/// ```
/// extern crate rust;
/// assert_eq!(true, rust::problems::negue(false));
/// assert_eq!(false, rust::problems::negue(true));
/// ```
pub fn negue(value:bool) -> bool {
    !value
}

/// A função `diga_ola` deve ser escrita de tal forma que receba como
/// parâmetro um argumento *string*. Deve retornar a *string* "Olá, ", seguida
/// do argumento recebido, mais um ponto final. A *string* recebida deve estar
/// limpa, ou seja, sem caracteres de espaço no começo ou no fim. Se a *string*
/// estiver vazia, retorna apenas "Olá!"
///
/// # Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!("Olá!", rust::problems::diga_ola(""));
/// assert_eq!("Olá!", rust::problems::diga_ola("    "));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("Paulo"));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("  Paulo  "));
/// assert_eq!("Olá, Paulo Henrique.", rust::problems::diga_ola("  Paulo Henrique  "));
/// ```
pub fn diga_ola(nome:&str) -> String {
    let nome_limpo = nome.trim();

    if nome_limpo.is_empty() {
        return "Olá!".to_string();
    }

    format!("Olá, {}.", &nome_limpo)
}

/// A função `lista_numeros_pares` deve receber um parâmetro numérico
/// inteiro que determina quantos números pares devem estar em um array que
/// será o retorno da função.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_numeros_pares(0).len());
/// assert_eq!(vec![2], rust::problems::lista_numeros_pares(1));
/// assert_eq!(vec![2, 4, 6, 8], rust::problems::lista_numeros_pares(4));
/// assert_eq!(vec![2, 4, 6, 8, 10], rust::problems::lista_numeros_pares(5));
/// assert_eq!(0, rust::problems::lista_numeros_pares(-1).len());
/// ```
pub fn lista_numeros_pares(quantos:i32) -> Vec<i32> {
    (1..quantos+1).map(|x| x*2).collect::<Vec<i32>>()
}

/// A função `lista_multiplos` deve receber dois parâmetros numéricos
/// inteiros e retornar uma lista de números inteiros. O tamanho da lista é
/// determinado pelo primeiro parâmetro, e o número base será o segundo
/// parâmetro.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_multiplos(0, 10).len());
/// assert_eq!(0, rust::problems::lista_multiplos(-1, 10).len());
/// assert_eq!(vec![-3, -2, -1], rust::problems::lista_multiplos(3, -1));
/// assert_eq!(0, rust::problems::lista_multiplos(3, 0).len());
/// assert_eq!(vec![10, 20, 30], rust::problems::lista_multiplos(3, 10));
/// ```
pub fn lista_multiplos(quantos:i32, base:i32) -> Vec<i32> {
    if base == 0 {
        return vec![];
    }

    let mut response = (1..quantos+1).map(|x| x*base).collect::<Vec<i32>>();

    if base < 1 {
        response.reverse();
    }

    response
}

/// A função `soma` deve receber um *array* de números inteiros, e retornar
/// a sua soma. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::soma(vec![]));
/// assert_eq!(1, rust::problems::soma(vec![1]));
/// assert_eq!(3, rust::problems::soma(vec![1, 2]));
/// ```
pub fn soma(lista:Vec<i32>) -> i32 {
    lista.iter().fold(0, |result, x| result + x)
}

/// A função `subtracao` deve receber um *array* de números inteiros, e
/// retornar a subtração de todos os elementos em sequência. Por exemplo,
/// subtracao([3,2,1]) deve retornar 0, e subtracao([10,2,3]) deve retornar 5.
/// Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::subtracao(vec![3, 2, 1]));
/// assert_eq!(5, rust::problems::subtracao(vec![10, 2, 3]));
/// assert_eq!(0, rust::problems::subtracao(vec![]));
/// assert_eq!(-1, rust::problems::subtracao(vec![1, 2]));
/// assert_eq!(4, rust::problems::subtracao(vec![-1, -2, -3]));
/// assert_eq!(3, rust::problems::subtracao(vec![9, 3, 2, 1]));
/// ```
pub fn subtracao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result - x)
}

/// A função `multiplicação` deve receber um *array* de números inteiros, e
/// retornar o seu produto. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(6, rust::problems::multiplicacao(vec![1, 2, 3]));
/// assert_eq!(0, rust::problems::multiplicacao(vec![]));
/// assert_eq!(-8, rust::problems::multiplicacao(vec![-2, 1, 4]));
/// assert_eq!(8, rust::problems::multiplicacao(vec![-2, -1, 4]));
pub fn multiplicacao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista.iter().fold(1, |result, x| result * x)
}

/// A função `divisao` deve receber um *array* de números inteiros, e
/// retornar o resultado da sequência de divisões por cada elemento. Por
/// exemplo, divisão([16, 4, 2]) deve retornar 2, e divisão([100,2,10]) deve
/// retornar 5. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(2, rust::problems::divisao(vec![5, 2]));
/// assert_eq!(0, rust::problems::divisao(vec![]));
/// assert_eq!(0, rust::problems::divisao(vec![0]));
/// assert_eq!(2, rust::problems::divisao(vec![16, 4, 2]));
/// assert_eq!(5, rust::problems::divisao(vec![100, 2, 10]));
/// assert_eq!(0, rust::problems::divisao(vec![0, 1]));
/// //assert_eq!(0, rust::problems::divisao(vec![1, 0]));
pub fn divisao(lista:Vec<i32>) ->i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result / x)
}

/// A função `maior` deve receber um *array* de números inteiros e retornar
/// qual é o maior deles.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(100, rust::problems::maior(vec![0, 1 ,100]));
/// assert_eq!(0, rust::problems::maior(vec![0]));
pub fn maior(lista:Vec<i32>)-> i32 {
    lista.iter().fold(lista[0], |result, x| if *x > result {*x} else {result})
}

/// A função `intersecao` deve receber dois *arrays* contendo números
/// inteiros, e retornar a interseção entre os conjuntos, ou seja, um *array*
/// que contenha apenas os números que estejam contidos nos dois *arrays*
/// passados para a função.
///
/// Examples
///
/// ```
/// assert_eq!(0, rust::problems::intersecao(vec![], vec![]).len());
/// assert_eq!(0, rust::problems::intersecao(vec![1, 2], vec![3, 4]).len());
/// assert_eq!(vec![2], rust::problems::intersecao(vec![1, 2], vec![2, 3]));
pub fn intersecao(a:Vec<i32>, b:Vec<i32>) -> Vec<i32> {
    let _a:HashSet<i32> = a.iter().cloned().collect();
    let _b:HashSet<i32> = b.iter().cloned().collect();

    _a.intersection(&_b).cloned().collect::<Vec<i32>>()
}
<|endoftext|>


<commit_before>// This should fail to compile if any of these code examples are wrong.

fn main() {
    // Doing the string conversions all in main so that the lifetimes can be inferred.

    let s = "I am a &str.";

    // &str => String
    let st: String = s.to_string();

    // String => &str
    let str: &str = st.as_slice();
}

// int ---------------------------------------------------------------

fn int_to_uint(x: int) -> uint {
    x.to_uint().unwrap()
}

fn int_to_string(x: int) -> String {
    x.to_string()
}

fn int_to_char(x: int) -> char {
    std::char::from_digit(x.to_uint().unwrap(), 10).unwrap()
}

// uint ---------------------------------------------------------------

fn uint_to_int(x: uint) -> int {
    x.to_int().unwrap()
}

fn uint_to_string(x: uint) -> String {
    x.to_string()
}

fn uint_to_char(x: uint) -> char {
    std::char::from_digit(x, 10).unwrap()
}

// String ---------------------------------------------------------------

fn string_to_int(x: String) -> int {
    x.parse().unwrap()
}

fn string_to_uint(x: String) -> uint {
    x.parse().unwrap()
}

fn string_to_char(x: String) -> char {
    x.char_at(0)
}

// char ---------------------------------------------------------------

fn char_to_int(x: char) -> int {
    std::char::to_digit(x, 10).unwrap().to_int().unwrap()
}

fn char_to_uint(x: char) -> uint {
    std::char::to_digit(x, 10).unwrap()
}

fn char_to_string(x: char) -> String {
    x.to_string()
}
<commit_msg>Add some happy path tests<commit_after>// This should fail to compile if any of these code examples are wrong.

fn main() {
    // Doing the string conversions all in main so that the lifetimes can be inferred.

    let s = "I am a &str.";

    // &str => String
    let st: String = s.to_string();

    // String => &str
    let str: &str = st.as_slice();
}

// int ---------------------------------------------------------------

fn int_to_uint(x: int) -> uint {
    x.to_uint().unwrap()
}

#[test]
fn test_int_to_uint_happy() {
    let x = 3i;
    let y = 3u;
    assert_eq!(y, int_to_uint(x));
}

fn int_to_string(x: int) -> String {
    x.to_string()
}

#[test]
fn test_int_to_string_happy() {
    let x = 3i;
    let y = "3";
    assert_eq!(y, int_to_string(x));
}

fn int_to_char(x: int) -> char {
    std::char::from_digit(x.to_uint().unwrap(), 10).unwrap()
}

#[test]
fn test_int_to_char_happy() {
    let x = 3i;
    let y = '3';
    assert_eq!(y, int_to_char(x));
}

// uint ---------------------------------------------------------------

fn uint_to_int(x: uint) -> int {
    x.to_int().unwrap()
}

#[test]
fn test_uint_to_int_happy() {
    let x = 3u;
    let y = 3i;
    assert_eq!(y, uint_to_int(x));
}

fn uint_to_string(x: uint) -> String {
    x.to_string()
}

#[test]
fn test_uint_to_string_happy() {
    let x = 3u;
    let y = "3";
    assert_eq!(y, uint_to_string(x));
}

fn uint_to_char(x: uint) -> char {
    std::char::from_digit(x, 10).unwrap()
}

#[test]
fn test_uint_to_char_happy() {
    let x = 3u;
    let y = '3';
    assert_eq!(y, uint_to_char(x));
}

// String ---------------------------------------------------------------

fn string_to_int(x: String) -> int {
    x.parse().unwrap()
}

#[test]
fn test_string_to_int_happy() {
    let x = "3".to_string();
    let y = 3i;
    assert_eq!(y, string_to_int(x));
}

fn string_to_uint(x: String) -> uint {
    x.parse().unwrap()
}

#[test]
fn test_string_to_uint_happy() {
    let x = "3".to_string();
    let y = 3u;
    assert_eq!(y, string_to_uint(x));
}

fn string_to_char(x: String) -> char {
    x.char_at(0)
}

#[test]
fn test_string_to_char_happy() {
    let x = "3".to_string();
    let y = '3';
    assert_eq!(y, string_to_char(x));
}

// char ---------------------------------------------------------------

fn char_to_int(x: char) -> int {
    std::char::to_digit(x, 10).unwrap().to_int().unwrap()
}

#[test]
fn test_char_to_int_happy() {
    let x = '3';
    let y = 3i;
    assert_eq!(y, char_to_int(x));
}

fn char_to_uint(x: char) -> uint {
    std::char::to_digit(x, 10).unwrap()
}

#[test]
fn test_char_to_uint_happy() {
    let x = '3';
    let y = 3u;
    assert_eq!(y, char_to_uint(x));
}

fn char_to_string(x: char) -> String {
    x.to_string()
}

#[test]
fn test_char_to_string_happy() {
    let x = '3';
    let y = "3";
    assert_eq!(y, char_to_string(x));
}
<|endoftext|>


<commit_before>#![deny(anonymous_parameters, bare_trait_object, box_pointers, const_err, dead_code, deprecated,
        elided_lifetime_in_path, exceeding_bitshifts, ignored_generic_bounds,
        illegal_floating_point_literal_pattern, improper_ctypes, incoherent_fundamental_impls,
        invalid_type_param_default, late_bound_lifetime_arguments, legacy_constructor_visibility,
        legacy_directory_ownership, legacy_imports, missing_copy_implementations,
        missing_debug_implementations, missing_docs, missing_fragment_specifier,
        mutable_transmutes, no_mangle_const_items, no_mangle_generic_items, non_camel_case_types,
        non_shorthand_field_patterns, non_snake_case, non_upper_case_globals,
        overflowing_literals, parenthesized_params_in_types_and_modules, path_statements,
        patterns_in_fns_without_body, plugin_as_library, private_in_public, private_no_mangle_fns,
        private_no_mangle_statics, pub_use_of_private_extern_crate, renamed_and_removed_lints,
        safe_extern_statics, safe_packed_borrows, single_use_lifetime, stable_features,
        trivial_casts, trivial_numeric_casts, tyvar_behind_raw_pointer, unconditional_recursion,
        unions_with_drop_fields, unknown_crate_types, unknown_lints, unreachable_code,
        unreachable_patterns, unreachable_pub, unsafe_code, unstable_features, unused_allocation,
        unused_assignments, unused_attributes, unused_comparisons, unused_doc_comment,
        unused_extern_crates, unused_features, unused_import_braces, unused_imports,
        unused_macros, unused_must_use, unused_mut, unused_parens, unused_qualifications,
        unused_results, unused_unsafe, unused_variables, variant_size_differences, while_true)]
#![warn(unknown_lints)]
#![allow(box_pointers, elided_lifetime_in_path, missing_debug_implementations,
         single_use_lifetime, trivial_casts, unused_results, variant_size_differences, warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

extern crate ci_info;
extern crate clap;
extern crate fern;
extern crate glob;
extern crate indexmap;
#[macro_use]
extern crate log;
extern crate rand;
extern crate run_script;
extern crate rust_info;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate shell2batch;
extern crate toml;

// make types public for docs
pub mod types;

mod logger;
mod config;
mod cache;
mod descriptor;
mod environment;
mod command;
mod installer;
mod scriptengine;
mod condition;
mod runner;
mod cli;
mod version;

#[cfg(test)]
#[path = "./main_test.rs"]
mod main_test;

#[cfg(test)]
#[path = "./test.rs"]
mod test;

fn main() {
    cli::run_cli();
}
<commit_msg>update lint rules<commit_after>#![deny(anonymous_parameters, bare_trait_object, box_pointers, const_err, dead_code, deprecated,
        elided_lifetime_in_path, exceeding_bitshifts, ignored_generic_bounds,
        illegal_floating_point_literal_pattern, improper_ctypes, incoherent_fundamental_impls,
        invalid_type_param_default, late_bound_lifetime_arguments, legacy_constructor_visibility,
        legacy_directory_ownership, legacy_imports, missing_copy_implementations,
        missing_debug_implementations, missing_docs, missing_fragment_specifier,
        mutable_transmutes, no_mangle_const_items, no_mangle_generic_items, non_camel_case_types,
        non_shorthand_field_patterns, non_snake_case, non_upper_case_globals,
        overflowing_literals, parenthesized_params_in_types_and_modules, path_statements,
        patterns_in_fns_without_body, plugin_as_library, private_in_public, private_no_mangle_fns,
        private_no_mangle_statics, pub_use_of_private_extern_crate, renamed_and_removed_lints,
        safe_extern_statics, safe_packed_borrows, single_use_lifetime, stable_features,
        trivial_casts, trivial_numeric_casts, tyvar_behind_raw_pointer, unconditional_recursion,
        unions_with_drop_fields, unknown_crate_types, unreachable_code, unreachable_patterns,
        unreachable_pub, unsafe_code, unstable_features, unused_allocation, unused_assignments,
        unused_attributes, unused_comparisons, unused_doc_comment, unused_extern_crates,
        unused_features, unused_import_braces, unused_imports, unused_macros, unused_must_use,
        unused_mut, unused_parens, unused_qualifications, unused_results, unused_unsafe,
        unused_variables, variant_size_differences, while_true)]
#![warn(unknown_lints)]
#![allow(box_pointers, elided_lifetime_in_path, missing_debug_implementations,
         single_use_lifetime, trivial_casts, unused_results, variant_size_differences, warnings)]
#![cfg_attr(feature = "clippy", feature(plugin))]

//! # cargo-make
//!
//! Rust task runner and build tool.

//! The cargo-make task runner enables to define and configure sets of tasks and run them as a flow.

//! A task is a command or a script to execute.

//! Tasks can have dependencies which are also tasks that will be executed before the task itself.

//! With a simple toml based configuration file, you can define a multi platform build script that can run build, test,
//! documentation generation, bench tests execution, security validations and more by running a single command.
//!
//! ## Installation
//! In order to install, just run the following command
//!
//! ```sh
//! cargo install cargo-make
//! ```
//!
//! This will install cargo-make in your ~/.cargo/bin.

//! Make sure to add ~/.cargo/bin directory to your PATH variable.
//!
//! # Contributing
//! See [contributing guide](https://github.com/sagiegurari/simple_redis/blob/master/.github/CONTRIBUTING.md)
//!
//! # License
//! Developed by Sagie Gur-Ari and licensed under the
//! [Apache 2](https://github.com/sagiegurari/simple_redis/blob/master/LICENSE) open source license.
//!

extern crate ci_info;
extern crate clap;
extern crate fern;
extern crate glob;
extern crate indexmap;
#[macro_use]
extern crate log;
extern crate rand;
extern crate run_script;
extern crate rust_info;
extern crate semver;
#[macro_use]
extern crate serde_derive;
extern crate shell2batch;
extern crate toml;

// make types public for docs
pub mod types;

mod logger;
mod config;
mod cache;
mod descriptor;
mod environment;
mod command;
mod installer;
mod scriptengine;
mod condition;
mod runner;
mod cli;
mod version;

#[cfg(test)]
#[path = "./main_test.rs"]
mod main_test;

#[cfg(test)]
#[path = "./test.rs"]
mod test;

fn main() {
    cli::run_cli();
}
<|endoftext|>


<commit_before>extern crate sdl2;

mod phi;
mod views;

fn main() {
    self::phi::spawn("Arcade Shooter", |_|{
        Box::new(self::views::DefaultView)
    });
}
<commit_msg>load view A by default<commit_after>extern crate sdl2;

mod phi;
mod views;

fn main() {
    self::phi::spawn("Arcade Shooter", |_|{
        Box::new(self::views::ViewA)
    });
}
<|endoftext|>


<commit_before>use anyhow::Result;
use smallvec::{smallvec, SmallVec};

use crate::{
    analysis::dis,
    module::{Module, Permissions},
    VA,
};

/// The type and destination of a control flow.
#[derive(Debug, Clone, Copy)]
pub enum Flow {
    // mov eax, eax
    // push ebp
    Fallthrough(VA),

    // call [0x401000]
    Call(VA),

    // call [eax]
    //IndirectCall { src: Rva },

    // jmp 0x401000
    UnconditionalJump(VA),

    // jmp eax
    //UnconditionalIndirectJump { src: Rva, dst: Rva },

    // jnz 0x401000
    ConditionalJump(VA),

    // jnz eax
    //ConditionalIndirectJump { src: Rva },

    // cmov 0x1
    ConditionalMove(VA),
}

impl Flow {
    pub fn va(&self) -> VA {
        match *self {
            Flow::Fallthrough(va) => va,
            Flow::Call(va) => va,
            Flow::UnconditionalJump(va) => va,
            Flow::ConditionalJump(va) => va,
            Flow::ConditionalMove(va) => va,
        }
    }

    /// create a new Flow with the va swapped out for the given va.
    /// useful when you have a flow edge that you want to reverse
    /// (e.g. from successor to predecessor).
    pub fn swap(&self, va: VA) -> Flow {
        match *self {
            Flow::Fallthrough(_) => Flow::Fallthrough(va),
            Flow::Call(_) => Flow::Call(va),
            Flow::UnconditionalJump(_) => Flow::UnconditionalJump(va),
            Flow::ConditionalJump(_) => Flow::ConditionalJump(va),
            Flow::ConditionalMove(_) => Flow::ConditionalMove(va),
        }
    }
}

/// most instructions have 1-2 flows, so attempt to store the inline.
pub type Flows = SmallVec<[Flow; 2]>;

fn is_executable(module: &Module, va: VA) -> bool {
    module.probe_va(va, Permissions::X)
}

pub fn get_call_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a CALL, then its a programming error. panic!
    // all CALLs should have an operand.
    let op = dis::get_first_operand(insn).expect("CALL has no operand");

    if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
        if is_executable(module, dst) {
            return Ok(smallvec![Flow::Call(dst)]);
        }
    }
    Ok(smallvec![])
}

pub fn get_jmp_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a JMP, then its a programming error. panic!
    // all JMPs should have an operand.
    let op = dis::get_first_operand(insn).expect("JMP has no target");

    if op.ty == zydis::OperandType::MEMORY
        && op.mem.scale == 0x4
        && op.mem.base == zydis::Register::NONE
        && op.mem.disp.has_displacement
    {
        // this looks like a switch table, e.g. `JMP [0x1000+ecx*4]`
        // it should probably be solved via emulation.
        // see analysis/pe/pointers.rs for some experiments looking at pointer tables.
        Ok(smallvec![])
    } else {
        if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
            if is_executable(module, dst) {
                return Ok(smallvec![Flow::UnconditionalJump(dst)]);
            }
        }
        Ok(smallvec![])
    }
}

pub fn get_cjmp_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a CJMP, then its a programming error. panic!
    // all conditional jumps should have an operand.
    let op = dis::get_first_operand(insn).expect("CJMP has no target");

    if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
        if is_executable(module, dst) {
            return Ok(smallvec![Flow::ConditionalJump(dst)]);
        }
    }
    Ok(smallvec![])
}

pub fn get_cmov_insn_flow(va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    let next = va + insn.length as u64;
    Ok(smallvec![Flow::ConditionalMove(next)])
}

pub fn get_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    let mut flows = match insn.mnemonic {
        zydis::Mnemonic::CALL => get_call_insn_flow(module, va, insn)?,

        zydis::Mnemonic::JMP => get_jmp_insn_flow(module, va, insn)?,

        zydis::Mnemonic::RET | zydis::Mnemonic::IRET | zydis::Mnemonic::IRETD | zydis::Mnemonic::IRETQ => smallvec![],

        zydis::Mnemonic::JB
        | zydis::Mnemonic::JBE
        | zydis::Mnemonic::JCXZ
        | zydis::Mnemonic::JECXZ
        | zydis::Mnemonic::JKNZD
        | zydis::Mnemonic::JKZD
        | zydis::Mnemonic::JL
        | zydis::Mnemonic::JLE
        | zydis::Mnemonic::JNB
        | zydis::Mnemonic::JNBE
        | zydis::Mnemonic::JNL
        | zydis::Mnemonic::JNLE
        | zydis::Mnemonic::JNO
        | zydis::Mnemonic::JNP
        | zydis::Mnemonic::JNS
        | zydis::Mnemonic::JNZ
        | zydis::Mnemonic::JO
        | zydis::Mnemonic::JP
        | zydis::Mnemonic::JRCXZ
        | zydis::Mnemonic::JS
        | zydis::Mnemonic::JZ => get_cjmp_insn_flow(module, va, insn)?,

        zydis::Mnemonic::CMOVB
        | zydis::Mnemonic::CMOVBE
        | zydis::Mnemonic::CMOVL
        | zydis::Mnemonic::CMOVLE
        | zydis::Mnemonic::CMOVNB
        | zydis::Mnemonic::CMOVNBE
        | zydis::Mnemonic::CMOVNL
        | zydis::Mnemonic::CMOVNLE
        | zydis::Mnemonic::CMOVNO
        | zydis::Mnemonic::CMOVNP
        | zydis::Mnemonic::CMOVNS
        | zydis::Mnemonic::CMOVNZ
        | zydis::Mnemonic::CMOVO
        | zydis::Mnemonic::CMOVP
        | zydis::Mnemonic::CMOVS
        | zydis::Mnemonic::CMOVZ => get_cmov_insn_flow(va, insn)?,

        // TODO: syscall, sysexit, sysret, vmcall, vmmcall
        _ => smallvec![],
    };

    if dis::does_insn_fallthrough(insn) {
        flows.push(Flow::Fallthrough(va + insn.length as u64))
    }

    Ok(flows)
}

#[cfg(test)]
mod tests {
    use crate::{analysis::cfg::flow::*, test::*};

    #[test]
    fn test_get_call_insn_flow() {
        // E8 00 00 00 00  CALL $+5
        // 90              NOP
        let module = load_shellcode32(b"\xE8\x00\x00\x00\x00\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_call_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x5);
    }

    #[test]
    fn test_get_jmp_insn_flow() {
        // E9 00 00 00 00  JMP $+5
        // 90              NOP
        let module = load_shellcode32(b"\xE9\x00\x00\x00\x00\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_jmp_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x5);
    }

    #[test]
    fn test_get_cjmp_insn_flow() {
        // 75 01 JNZ $+1
        // CC    BREAK
        // 90    NOP
        let module = load_shellcode32(b"\x75\x01\xCC\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_cjmp_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x3);
    }

    #[test]
    fn test_get_cmov_insn_flow() {
        // 0F 44 C3  CMOVZ EAX, EBX
        // 90        NOP
        let module = load_shellcode32(b"\x0F\x44\xC3\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_cmov_insn_flow(0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x3);
    }
}
<commit_msg>clippy<commit_after>use anyhow::Result;
use smallvec::{smallvec, SmallVec};

use crate::{
    analysis::dis,
    module::{Module, Permissions},
    VA,
};

/// The type and destination of a control flow.
#[derive(Debug, Clone, Copy)]
pub enum Flow {
    // mov eax, eax
    // push ebp
    Fallthrough(VA),

    // call [0x401000]
    Call(VA),

    // call [eax]
    //IndirectCall { src: Rva },

    // jmp 0x401000
    UnconditionalJump(VA),

    // jmp eax
    //UnconditionalIndirectJump { src: Rva, dst: Rva },

    // jnz 0x401000
    ConditionalJump(VA),

    // jnz eax
    //ConditionalIndirectJump { src: Rva },

    // cmov 0x1
    ConditionalMove(VA),
}

impl Flow {
    pub fn va(&self) -> VA {
        match *self {
            Flow::Fallthrough(va) => va,
            Flow::Call(va) => va,
            Flow::UnconditionalJump(va) => va,
            Flow::ConditionalJump(va) => va,
            Flow::ConditionalMove(va) => va,
        }
    }

    /// create a new Flow with the va swapped out for the given va.
    /// useful when you have a flow edge that you want to reverse
    /// (e.g. from successor to predecessor).
    #[must_use]
    pub fn swap(&self, va: VA) -> Flow {
        match *self {
            Flow::Fallthrough(_) => Flow::Fallthrough(va),
            Flow::Call(_) => Flow::Call(va),
            Flow::UnconditionalJump(_) => Flow::UnconditionalJump(va),
            Flow::ConditionalJump(_) => Flow::ConditionalJump(va),
            Flow::ConditionalMove(_) => Flow::ConditionalMove(va),
        }
    }
}

/// most instructions have 1-2 flows, so attempt to store the inline.
pub type Flows = SmallVec<[Flow; 2]>;

fn is_executable(module: &Module, va: VA) -> bool {
    module.probe_va(va, Permissions::X)
}

pub fn get_call_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a CALL, then its a programming error. panic!
    // all CALLs should have an operand.
    let op = dis::get_first_operand(insn).expect("CALL has no operand");

    if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
        if is_executable(module, dst) {
            return Ok(smallvec![Flow::Call(dst)]);
        }
    }
    Ok(smallvec![])
}

pub fn get_jmp_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a JMP, then its a programming error. panic!
    // all JMPs should have an operand.
    let op = dis::get_first_operand(insn).expect("JMP has no target");

    if op.ty == zydis::OperandType::MEMORY
        && op.mem.scale == 0x4
        && op.mem.base == zydis::Register::NONE
        && op.mem.disp.has_displacement
    {
        // this looks like a switch table, e.g. `JMP [0x1000+ecx*4]`
        // it should probably be solved via emulation.
        // see analysis/pe/pointers.rs for some experiments looking at pointer tables.
        Ok(smallvec![])
    } else {
        if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
            if is_executable(module, dst) {
                return Ok(smallvec![Flow::UnconditionalJump(dst)]);
            }
        }
        Ok(smallvec![])
    }
}

pub fn get_cjmp_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    // if this is not a CJMP, then its a programming error. panic!
    // all conditional jumps should have an operand.
    let op = dis::get_first_operand(insn).expect("CJMP has no target");

    if let Ok(Some(dst)) = dis::get_operand_xref(module, va, insn, op) {
        if is_executable(module, dst) {
            return Ok(smallvec![Flow::ConditionalJump(dst)]);
        }
    }
    Ok(smallvec![])
}

pub fn get_cmov_insn_flow(va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    let next = va + insn.length as u64;
    Ok(smallvec![Flow::ConditionalMove(next)])
}

pub fn get_insn_flow(module: &Module, va: VA, insn: &zydis::DecodedInstruction) -> Result<Flows> {
    let mut flows = match insn.mnemonic {
        zydis::Mnemonic::CALL => get_call_insn_flow(module, va, insn)?,

        zydis::Mnemonic::JMP => get_jmp_insn_flow(module, va, insn)?,

        zydis::Mnemonic::RET | zydis::Mnemonic::IRET | zydis::Mnemonic::IRETD | zydis::Mnemonic::IRETQ => smallvec![],

        zydis::Mnemonic::JB
        | zydis::Mnemonic::JBE
        | zydis::Mnemonic::JCXZ
        | zydis::Mnemonic::JECXZ
        | zydis::Mnemonic::JKNZD
        | zydis::Mnemonic::JKZD
        | zydis::Mnemonic::JL
        | zydis::Mnemonic::JLE
        | zydis::Mnemonic::JNB
        | zydis::Mnemonic::JNBE
        | zydis::Mnemonic::JNL
        | zydis::Mnemonic::JNLE
        | zydis::Mnemonic::JNO
        | zydis::Mnemonic::JNP
        | zydis::Mnemonic::JNS
        | zydis::Mnemonic::JNZ
        | zydis::Mnemonic::JO
        | zydis::Mnemonic::JP
        | zydis::Mnemonic::JRCXZ
        | zydis::Mnemonic::JS
        | zydis::Mnemonic::JZ => get_cjmp_insn_flow(module, va, insn)?,

        zydis::Mnemonic::CMOVB
        | zydis::Mnemonic::CMOVBE
        | zydis::Mnemonic::CMOVL
        | zydis::Mnemonic::CMOVLE
        | zydis::Mnemonic::CMOVNB
        | zydis::Mnemonic::CMOVNBE
        | zydis::Mnemonic::CMOVNL
        | zydis::Mnemonic::CMOVNLE
        | zydis::Mnemonic::CMOVNO
        | zydis::Mnemonic::CMOVNP
        | zydis::Mnemonic::CMOVNS
        | zydis::Mnemonic::CMOVNZ
        | zydis::Mnemonic::CMOVO
        | zydis::Mnemonic::CMOVP
        | zydis::Mnemonic::CMOVS
        | zydis::Mnemonic::CMOVZ => get_cmov_insn_flow(va, insn)?,

        // TODO: syscall, sysexit, sysret, vmcall, vmmcall
        _ => smallvec![],
    };

    if dis::does_insn_fallthrough(insn) {
        flows.push(Flow::Fallthrough(va + insn.length as u64))
    }

    Ok(flows)
}

#[cfg(test)]
mod tests {
    use crate::{analysis::cfg::flow::*, test::*};

    #[test]
    fn test_get_call_insn_flow() {
        // E8 00 00 00 00  CALL $+5
        // 90              NOP
        let module = load_shellcode32(b"\xE8\x00\x00\x00\x00\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_call_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x5);
    }

    #[test]
    fn test_get_jmp_insn_flow() {
        // E9 00 00 00 00  JMP $+5
        // 90              NOP
        let module = load_shellcode32(b"\xE9\x00\x00\x00\x00\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_jmp_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x5);
    }

    #[test]
    fn test_get_cjmp_insn_flow() {
        // 75 01 JNZ $+1
        // CC    BREAK
        // 90    NOP
        let module = load_shellcode32(b"\x75\x01\xCC\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_cjmp_insn_flow(&module, 0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x3);
    }

    #[test]
    fn test_get_cmov_insn_flow() {
        // 0F 44 C3  CMOVZ EAX, EBX
        // 90        NOP
        let module = load_shellcode32(b"\x0F\x44\xC3\x90");
        let insn = read_insn(&module, 0x0);
        let flows = get_cmov_insn_flow(0x0, &insn).unwrap();
        assert_eq!(flows[0].va(), 0x3);
    }
}
<|endoftext|>


<commit_before>//! Database used for testing `hir_def`.

use std::{
    fmt, panic,
    sync::{Arc, Mutex},
};

use base_db::SourceDatabase;
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
use hir_expand::db::AstDatabase;
use hir_expand::diagnostics::Diagnostic;
use hir_expand::diagnostics::DiagnosticSinkBuilder;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use syntax::{TextRange, TextSize};
use test_utils::extract_annotations;

use crate::{db::DefDatabase, ModuleDefId};

#[salsa::database(
    base_db::SourceDatabaseExtStorage,
    base_db::SourceDatabaseStorage,
    hir_expand::db::AstDatabaseStorage,
    crate::db::InternDatabaseStorage,
    crate::db::DefDatabaseStorage
)]
#[derive(Default)]
pub(crate) struct TestDB {
    storage: salsa::Storage<TestDB>,
    events: Mutex<Option<Vec<salsa::Event>>>,
}

impl Upcast<dyn AstDatabase> for TestDB {
    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn DefDatabase> for TestDB {
    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
        &*self
    }
}

impl salsa::Database for TestDB {
    fn salsa_event(&self, event: salsa::Event) {
        let mut events = self.events.lock().unwrap();
        if let Some(events) = &mut *events {
            events.push(event);
        }
    }
}

impl fmt::Debug for TestDB {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TestDB").finish()
    }
}

impl panic::RefUnwindSafe for TestDB {}

impl FileLoader for TestDB {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        FileLoaderDelegate(self).file_text(file_id)
    }
    fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        FileLoaderDelegate(self).resolve_path(anchor, path)
    }
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        FileLoaderDelegate(self).relevant_crates(file_id)
    }
}

impl TestDB {
    pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId {
        for &krate in self.relevant_crates(file_id).iter() {
            let crate_def_map = self.crate_def_map(krate);
            for (local_id, data) in crate_def_map.modules.iter() {
                if data.origin.file_id() == Some(file_id) {
                    return crate::ModuleId { krate, local_id };
                }
            }
        }
        panic!("Can't find module for file")
    }

    pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
        *self.events.lock().unwrap() = Some(Vec::new());
        f();
        self.events.lock().unwrap().take().unwrap()
    }

    pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
        let events = self.log(f);
        events
            .into_iter()
            .filter_map(|e| match e.kind {
                // This pretty horrible, but `Debug` is the only way to inspect
                // QueryDescriptor at the moment.
                salsa::EventKind::WillExecute { database_key } => {
                    Some(format!("{:?}", database_key.debug(self)))
                }
                _ => None,
            })
            .collect()
    }

    pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
        let mut files = Vec::new();
        let crate_graph = self.crate_graph();
        for krate in crate_graph.iter() {
            let crate_def_map = self.crate_def_map(krate);
            for (module_id, _) in crate_def_map.modules.iter() {
                let file_id = crate_def_map[module_id].origin.file_id();
                files.extend(file_id)
            }
        }
        assert!(!files.is_empty());
        files
            .into_iter()
            .filter_map(|file_id| {
                let text = self.file_text(file_id);
                let annotations = extract_annotations(&text);
                if annotations.is_empty() {
                    return None;
                }
                Some((file_id, annotations))
            })
            .collect()
    }

    pub(crate) fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
        let crate_graph = self.crate_graph();
        for krate in crate_graph.iter() {
            let crate_def_map = self.crate_def_map(krate);

            let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
            for (module_id, module) in crate_def_map.modules.iter() {
                crate_def_map.add_diagnostics(self, module_id, &mut sink);

                for decl in module.scope.declarations() {
                    if let ModuleDefId::FunctionId(it) = decl {
                        let source_map = self.body_with_source_map(it.into()).1;
                        source_map.add_diagnostics(self, &mut sink);
                    }
                }
            }
        }
    }

    pub(crate) fn check_diagnostics(&self) {
        let db: &TestDB = self;
        let annotations = db.extract_annotations();
        assert!(!annotations.is_empty());

        let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
        db.diagnostics(|d| {
            let src = d.display_source();
            let root = db.parse_or_expand(src.file_id).unwrap();

            // Place all diagnostics emitted in macro files on the original caller.
            // Note that this does *not* match IDE behavior.
            let mut src = src.map(|ptr| ptr.to_node(&root));
            while let Some(exp) = src.file_id.call_node(db) {
                src = exp;
            }

            let file_id = src.file_id.original_file(db);
            let range = src.value.text_range();
            let message = d.message().to_owned();
            actual.entry(file_id).or_default().push((range, message));
        });

        for (file_id, diags) in actual.iter_mut() {
            diags.sort_by_key(|it| it.0.start());
            let text = db.file_text(*file_id);
            // For multiline spans, place them on line start
            for (range, content) in diags {
                if text[*range].contains('\n') {
                    *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
                    *content = format!("... {}", content);
                }
            }
        }

        assert_eq!(annotations, actual);
    }
}
<commit_msg>Use `original_file_range` in `TestDB`<commit_after>//! Database used for testing `hir_def`.

use std::{
    fmt, panic,
    sync::{Arc, Mutex},
};

use base_db::SourceDatabase;
use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast};
use hir_expand::db::AstDatabase;
use hir_expand::diagnostics::Diagnostic;
use hir_expand::diagnostics::DiagnosticSinkBuilder;
use rustc_hash::FxHashMap;
use rustc_hash::FxHashSet;
use syntax::{TextRange, TextSize};
use test_utils::extract_annotations;

use crate::{db::DefDatabase, ModuleDefId};

#[salsa::database(
    base_db::SourceDatabaseExtStorage,
    base_db::SourceDatabaseStorage,
    hir_expand::db::AstDatabaseStorage,
    crate::db::InternDatabaseStorage,
    crate::db::DefDatabaseStorage
)]
#[derive(Default)]
pub(crate) struct TestDB {
    storage: salsa::Storage<TestDB>,
    events: Mutex<Option<Vec<salsa::Event>>>,
}

impl Upcast<dyn AstDatabase> for TestDB {
    fn upcast(&self) -> &(dyn AstDatabase + 'static) {
        &*self
    }
}

impl Upcast<dyn DefDatabase> for TestDB {
    fn upcast(&self) -> &(dyn DefDatabase + 'static) {
        &*self
    }
}

impl salsa::Database for TestDB {
    fn salsa_event(&self, event: salsa::Event) {
        let mut events = self.events.lock().unwrap();
        if let Some(events) = &mut *events {
            events.push(event);
        }
    }
}

impl fmt::Debug for TestDB {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("TestDB").finish()
    }
}

impl panic::RefUnwindSafe for TestDB {}

impl FileLoader for TestDB {
    fn file_text(&self, file_id: FileId) -> Arc<String> {
        FileLoaderDelegate(self).file_text(file_id)
    }
    fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> {
        FileLoaderDelegate(self).resolve_path(anchor, path)
    }
    fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> {
        FileLoaderDelegate(self).relevant_crates(file_id)
    }
}

impl TestDB {
    pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId {
        for &krate in self.relevant_crates(file_id).iter() {
            let crate_def_map = self.crate_def_map(krate);
            for (local_id, data) in crate_def_map.modules.iter() {
                if data.origin.file_id() == Some(file_id) {
                    return crate::ModuleId { krate, local_id };
                }
            }
        }
        panic!("Can't find module for file")
    }

    pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
        *self.events.lock().unwrap() = Some(Vec::new());
        f();
        self.events.lock().unwrap().take().unwrap()
    }

    pub(crate) fn log_executed(&self, f: impl FnOnce()) -> Vec<String> {
        let events = self.log(f);
        events
            .into_iter()
            .filter_map(|e| match e.kind {
                // This pretty horrible, but `Debug` is the only way to inspect
                // QueryDescriptor at the moment.
                salsa::EventKind::WillExecute { database_key } => {
                    Some(format!("{:?}", database_key.debug(self)))
                }
                _ => None,
            })
            .collect()
    }

    pub(crate) fn extract_annotations(&self) -> FxHashMap<FileId, Vec<(TextRange, String)>> {
        let mut files = Vec::new();
        let crate_graph = self.crate_graph();
        for krate in crate_graph.iter() {
            let crate_def_map = self.crate_def_map(krate);
            for (module_id, _) in crate_def_map.modules.iter() {
                let file_id = crate_def_map[module_id].origin.file_id();
                files.extend(file_id)
            }
        }
        assert!(!files.is_empty());
        files
            .into_iter()
            .filter_map(|file_id| {
                let text = self.file_text(file_id);
                let annotations = extract_annotations(&text);
                if annotations.is_empty() {
                    return None;
                }
                Some((file_id, annotations))
            })
            .collect()
    }

    pub(crate) fn diagnostics<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
        let crate_graph = self.crate_graph();
        for krate in crate_graph.iter() {
            let crate_def_map = self.crate_def_map(krate);

            let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
            for (module_id, module) in crate_def_map.modules.iter() {
                crate_def_map.add_diagnostics(self, module_id, &mut sink);

                for decl in module.scope.declarations() {
                    if let ModuleDefId::FunctionId(it) = decl {
                        let source_map = self.body_with_source_map(it.into()).1;
                        source_map.add_diagnostics(self, &mut sink);
                    }
                }
            }
        }
    }

    pub(crate) fn check_diagnostics(&self) {
        let db: &TestDB = self;
        let annotations = db.extract_annotations();
        assert!(!annotations.is_empty());

        let mut actual: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
        db.diagnostics(|d| {
            let src = d.display_source();
            let root = db.parse_or_expand(src.file_id).unwrap();

            let node = src.map(|ptr| ptr.to_node(&root));
            let frange = node.as_ref().original_file_range(db);

            let message = d.message().to_owned();
            actual.entry(frange.file_id).or_default().push((frange.range, message));
        });

        for (file_id, diags) in actual.iter_mut() {
            diags.sort_by_key(|it| it.0.start());
            let text = db.file_text(*file_id);
            // For multiline spans, place them on line start
            for (range, content) in diags {
                if text[*range].contains('\n') {
                    *range = TextRange::new(range.start(), range.start() + TextSize::from(1));
                    *content = format!("... {}", content);
                }
            }
        }

        assert_eq!(annotations, actual);
    }
}
<|endoftext|>


<commit_before>use std::thread;
use std::time::Duration;

use rand::{thread_rng, Rng};

use rustyline::error::ReadlineError;
use rustyline::{Editor, ExternalPrinter};

fn main() {
    env_logger::init();
    let mut rl = Editor::<()>::new();
    let mut printer = rl.create_external_printer().expect("No printer");
    thread::spawn(move || {
        let mut rng = thread_rng();
        let mut i = 0usize;
        loop {
            printer
                .print(format!("External message #{}", i))
                .expect("External print failure");
            let wait_ms = rng.gen_range(1..500);
            thread::sleep(Duration::from_millis(wait_ms));
            i += 1;
        }
    });

    loop {
        let readline = rl.readline(">>");
        match readline {
            Ok(line) => {
                rl.add_history_entry(line.as_str());
                println!("Line: {}", line);
            }
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }
    }
}
<commit_msg>Simplify external_print example<commit_after>use std::thread;
use std::time::Duration;

use rand::{thread_rng, Rng};

use rustyline::{Editor, ExternalPrinter, Result};

fn main() -> Result<()> {
    let mut rl = Editor::<()>::new();
    let mut printer = rl.create_external_printer()?;
    thread::spawn(move || {
        let mut rng = thread_rng();
        let mut i = 0usize;
        loop {
            printer
                .print(format!("External message #{}", i))
                .expect("External print failure");
            let wait_ms = rng.gen_range(1000..10000);
            thread::sleep(Duration::from_millis(wait_ms));
            i += 1;
        }
    });

    loop {
        let line = rl.readline(">>")?;
        rl.add_history_entry(line.as_str());
        println!("Line: {}", line);
    }
}
<|endoftext|>