diff --git a/CHANGELOG.md b/CHANGELOG.md index 30b8b1542f..d493fcdb0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [#607](https://github.com/FuelLabs/fuel-vm/pull/607): The `Interpreter` expects the third generic argument during type definition that specifies the implementer of the `EcalHandler` trait for `ecal` opcode. - [#609](https://github.com/FuelLabs/fuel-vm/pull/609): Checked transactions (`Create`, `Script`, and `Mint`) now enforce a maximum size. The maximum size is specified by `MAX_TRANSACTION_SIZE` in the transaction parameters, under consensus parameters. Checking a transaction above this size raises `CheckError::TransactionSizeLimitExceeded`. - [#617](https://github.com/FuelLabs/fuel-vm/pull/617): Makes memory outside `$is..$ssp` range not executable. Separates `ErrorFlag` into `InvalidFlags`, `MemoryNotExecutable` and `InvalidInstruction`. Fixes related tests. +- [#619](https://github.com/FuelLabs/fuel-vm/pull/619): Avoid possible truncation of higher bits. It may invalidate the code that truncated higher bits causing different behavior on 32-bit vs. 64-bit systems. ## [Version 0.39.0] diff --git a/fuel-asm/src/lib.rs b/fuel-asm/src/lib.rs index 30f45ff2a0..7f1b075b1d 100644 --- a/fuel-asm/src/lib.rs +++ b/fuel-asm/src/lib.rs @@ -3,6 +3,7 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(feature = "std", doc = include_str!("../README.md"))] +#![deny(clippy::cast_possible_truncation)] #![deny(clippy::string_slice)] #![deny(missing_docs)] #![deny(unsafe_code)] diff --git a/fuel-asm/src/panic_instruction.rs b/fuel-asm/src/panic_instruction.rs index a912599b36..917661aeea 100644 --- a/fuel-asm/src/panic_instruction.rs +++ b/fuel-asm/src/panic_instruction.rs @@ -102,6 +102,7 @@ impl From for Word { } impl From for PanicInstruction { + #[allow(clippy::cast_possible_truncation)] fn from(val: Word) -> Self { // Safe to cast as we've shifted the 8 MSB. let reason_u8 = (val >> REASON_OFFSET) as u8; diff --git a/fuel-asm/src/unpack.rs b/fuel-asm/src/unpack.rs index a005a0fc93..0bd19b5b9d 100644 --- a/fuel-asm/src/unpack.rs +++ b/fuel-asm/src/unpack.rs @@ -62,26 +62,32 @@ pub(super) fn ra_imm18_from_bytes(bs: [u8; 3]) -> (RegId, Imm18) { (ra_from_bytes(bs), imm18_from_bytes(bs)) } +#[allow(clippy::cast_possible_truncation)] fn ra_from_u32(u: u32) -> RegId { RegId::new((u >> 18) as u8) } +#[allow(clippy::cast_possible_truncation)] fn rb_from_u32(u: u32) -> RegId { RegId::new((u >> 12) as u8) } +#[allow(clippy::cast_possible_truncation)] fn rc_from_u32(u: u32) -> RegId { RegId::new((u >> 6) as u8) } +#[allow(clippy::cast_possible_truncation)] fn rd_from_u32(u: u32) -> RegId { RegId::new(u as u8) } +#[allow(clippy::cast_possible_truncation)] fn imm06_from_u32(u: u32) -> Imm06 { Imm06::new(u as u8) } +#[allow(clippy::cast_possible_truncation)] fn imm12_from_u32(u: u32) -> Imm12 { Imm12::new(u as u16) } diff --git a/fuel-crypto/src/lib.rs b/fuel-crypto/src/lib.rs index fef28e025b..b8d9c69f35 100644 --- a/fuel-crypto/src/lib.rs +++ b/fuel-crypto/src/lib.rs @@ -8,6 +8,7 @@ #![warn(missing_docs)] #![deny(unsafe_code)] #![deny(unused_crate_dependencies)] +#![deny(clippy::cast_possible_truncation)] // Satisfy unused_crate_dependencies lint for self-dependency enabling test features #[cfg(test)] diff --git a/fuel-merkle/src/common/msb.rs b/fuel-merkle/src/common/msb.rs index 0655f6fe17..1193d3dd59 100644 --- a/fuel-merkle/src/common/msb.rs +++ b/fuel-merkle/src/common/msb.rs @@ -5,11 +5,11 @@ pub enum Bit { } trait GetBit { - fn get_bit(&self, bit_index: usize) -> Option; + fn get_bit(&self, bit_index: u32) -> Option; } impl GetBit for u8 { - fn get_bit(&self, bit_index: usize) -> Option { + fn get_bit(&self, bit_index: u32) -> Option { if bit_index < 8 { let mask = 1 << (7 - bit_index); let bit = self & mask; @@ -24,21 +24,21 @@ impl GetBit for u8 { } pub trait Msb { - fn get_bit_at_index_from_msb(&self, index: usize) -> Option; - fn common_prefix_count(&self, other: &Self) -> usize; + fn get_bit_at_index_from_msb(&self, index: u32) -> Option; + fn common_prefix_count(&self, other: &Self) -> u32; } impl Msb for [u8; N] { - fn get_bit_at_index_from_msb(&self, index: usize) -> Option { + fn get_bit_at_index_from_msb(&self, index: u32) -> Option { // The byte that contains the bit let byte_index = index / 8; // The bit within the containing byte let byte_bit_index = index % 8; - self.get(byte_index) + self.get(byte_index as usize) .and_then(|byte| byte.get_bit(byte_bit_index)) } - fn common_prefix_count(&self, other: &Self) -> usize { + fn common_prefix_count(&self, other: &Self) -> u32 { let mut count = 0; for (byte1, byte2) in self.iter().zip(other.iter()) { // For each pair of bytes, compute the similarity of each byte using @@ -49,10 +49,11 @@ impl Msb for [u8; N] { break } } - count as usize + count } } +#[allow(clippy::cast_possible_truncation)] #[cfg(test)] mod test { use crate::common::{ @@ -66,7 +67,7 @@ mod test { #[test] fn test_msb_for_bytes_1() { - const NUM_BITS: usize = size_of::() * 8; + const NUM_BITS: u32 = size_of::() as u32 * 8; let bytes: Bytes1 = [0b10101010]; let expected_n = u8::from_be_bytes(bytes); @@ -83,7 +84,7 @@ mod test { #[test] fn test_msb_for_bytes_2() { - const NUM_BITS: usize = size_of::() * 8; + const NUM_BITS: u32 = size_of::() as u32 * 8; let bytes: Bytes2 = [0b10101010, 0b10101010]; let expected_n = u16::from_be_bytes(bytes); @@ -100,7 +101,7 @@ mod test { #[test] fn test_msb_for_bytes_4() { - const NUM_BITS: usize = size_of::() * 8; + const NUM_BITS: u32 = size_of::() as u32 * 8; let bytes: Bytes4 = [0b10101010, 0b10101010, 0b10101010, 0b10101010]; let expected_n = u32::from_be_bytes(bytes); @@ -117,7 +118,7 @@ mod test { #[test] fn test_msb_for_bytes_8() { - const NUM_BITS: usize = size_of::() * 8; + const NUM_BITS: u32 = size_of::() as u32 * 8; let bytes: Bytes8 = [ 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b10101010, 0b10101010, diff --git a/fuel-merkle/src/common/node.rs b/fuel-merkle/src/common/node.rs index bd18355ed9..645007cf30 100644 --- a/fuel-merkle/src/common/node.rs +++ b/fuel-merkle/src/common/node.rs @@ -18,8 +18,9 @@ pub trait KeyFormatting { pub trait Node { type Key: KeyFormatting; - fn key_size_in_bits() -> usize { - mem::size_of::() * 8 + fn key_size_in_bits() -> u32 { + u32::try_from(mem::size_of::() * 8) + .expect("The key usually is several bytes") } fn height(&self) -> u32; diff --git a/fuel-merkle/src/common/path.rs b/fuel-merkle/src/common/path.rs index 63db8ebff3..6a202345ef 100644 --- a/fuel-merkle/src/common/path.rs +++ b/fuel-merkle/src/common/path.rs @@ -18,18 +18,18 @@ impl From for Instruction { } pub trait Path { - fn get_instruction(&self, index: usize) -> Option; + fn get_instruction(&self, index: u32) -> Option; } pub trait ComparablePath { - fn common_path_length(&self, other: &Self) -> usize; + fn common_path_length(&self, other: &Self) -> u32; } impl Path for T where T: Msb, { - fn get_instruction(&self, index: usize) -> Option { + fn get_instruction(&self, index: u32) -> Option { self.get_bit_at_index_from_msb(index).map(Into::into) } } @@ -38,7 +38,7 @@ impl ComparablePath for T where T: Msb, { - fn common_path_length(&self, other: &Self) -> usize { + fn common_path_length(&self, other: &Self) -> u32 { self.common_prefix_count(other) } } diff --git a/fuel-merkle/src/common/path_iterator.rs b/fuel-merkle/src/common/path_iterator.rs index 671e5fac7e..ac4ec27ee7 100644 --- a/fuel-merkle/src/common/path_iterator.rs +++ b/fuel-merkle/src/common/path_iterator.rs @@ -84,7 +84,7 @@ use crate::common::{ pub struct PathIter { leaf_key: T::Key, current: Option<(ChildResult, ChildResult)>, - current_offset: usize, + current_offset: u32, } impl PathIter @@ -137,7 +137,7 @@ where // 0 7 00 02 04 06 08 10 12 14 252 254 // 00 01 02 03 04 05 06 07 126 127 // - let initial_offset = T::key_size_in_bits() - root.height() as usize; + let initial_offset = T::key_size_in_bits() - root.height(); Self { leaf_key, current: Some(initial), diff --git a/fuel-merkle/src/lib.rs b/fuel-merkle/src/lib.rs index 91cbcd5e63..3bb72df028 100644 --- a/fuel-merkle/src/lib.rs +++ b/fuel-merkle/src/lib.rs @@ -1,6 +1,7 @@ #![cfg_attr(not(feature = "std"), no_std)] #![allow(clippy::bool_assert_comparison, clippy::identity_op)] #![deny(unused_crate_dependencies)] +#![deny(clippy::cast_possible_truncation)] #[cfg_attr(test, macro_use)] extern crate alloc; diff --git a/fuel-merkle/src/sparse/branch.rs b/fuel-merkle/src/sparse/branch.rs index 0abda4d262..4b56a67da2 100644 --- a/fuel-merkle/src/sparse/branch.rs +++ b/fuel-merkle/src/sparse/branch.rs @@ -40,7 +40,7 @@ where { let branch = if left_branch.node.is_leaf() && right_branch.node.is_leaf() { let parent_depth = left_branch.node.common_path_length(&right_branch.node); - let parent_height = (Node::max_height() - parent_depth) as u32; + let parent_height = Node::max_height() - parent_depth; let node = Node::create_node(&left_branch.node, &right_branch.node, parent_height); Branch { @@ -53,9 +53,10 @@ where if right_branch.node.is_node() { let mut current_node = right_branch.node; let path = right_branch.bits; - let parent_height = current_node.height() as usize + 1; + let parent_height = current_node.height() + 1; let stale_depth = ancestor_height - parent_height; - let placeholders = iter::repeat(Node::create_placeholder()).take(stale_depth); + let placeholders = + iter::repeat(Node::create_placeholder()).take(stale_depth as usize); for placeholder in placeholders { current_node = Node::create_node_on_path(&path, ¤t_node, &placeholder); @@ -66,9 +67,10 @@ where if left_branch.node.is_node() { let mut current_node = left_branch.node; let path = left_branch.bits; - let parent_height = current_node.height() as usize + 1; + let parent_height = current_node.height() + 1; let stale_depth = ancestor_height - parent_height; - let placeholders = iter::repeat(Node::create_placeholder()).take(stale_depth); + let placeholders = + iter::repeat(Node::create_placeholder()).take(stale_depth as usize); for placeholder in placeholders { current_node = Node::create_node_on_path(&path, ¤t_node, &placeholder); @@ -76,11 +78,8 @@ where } left_branch.node = current_node; } - let node = Node::create_node( - &left_branch.node, - &right_branch.node, - ancestor_height as u32, - ); + let node = + Node::create_node(&left_branch.node, &right_branch.node, ancestor_height); Branch { bits: left_branch.bits, node, diff --git a/fuel-merkle/src/sparse/merkle_tree.rs b/fuel-merkle/src/sparse/merkle_tree.rs index a862bf2102..3bf085d0f4 100644 --- a/fuel-merkle/src/sparse/merkle_tree.rs +++ b/fuel-merkle/src/sparse/merkle_tree.rs @@ -133,7 +133,7 @@ impl MerkleTree { } fn set_root_node(&mut self, node: Node) { - debug_assert!(node.is_leaf() || node.height() == Node::max_height() as u32); + debug_assert!(node.is_leaf() || node.height() == Node::max_height()); self.root_node = node; } } @@ -252,7 +252,7 @@ where } let mut nodes = Vec::::with_capacity(branches.len()); - let mut proximities = Vec::::with_capacity(branches.len()); + let mut proximities = Vec::::with_capacity(branches.len()); // Building the tree starts by merging all leaf nodes where possible. // Given a set of leaf nodes sorted left to right (i.e., keys are sorted @@ -336,9 +336,9 @@ where // node has the final height and forms the root node. let mut node = top.node; let path = top.bits; - let height = node.height() as usize; + let height = node.height(); let depth = Node::max_height() - height; - let placeholders = iter::repeat(Node::create_placeholder()).take(depth); + let placeholders = iter::repeat(Node::create_placeholder()).take(depth as usize); for placeholder in placeholders { node = Node::create_node_on_path(&path, &node, &placeholder); storage.insert(node.hash(), &node.as_ref().into())?; @@ -455,7 +455,7 @@ where // Merge placeholders let ancestor_depth = requested_leaf_node.common_path_length(actual_leaf_node); - let stale_depth = cmp::max(side_nodes.len(), ancestor_depth); + let stale_depth = cmp::max(side_nodes.len(), ancestor_depth as usize); let placeholders_count = stale_depth - side_nodes.len(); let placeholders = iter::repeat(Node::create_placeholder()).take(placeholders_count); diff --git a/fuel-merkle/src/sparse/node.rs b/fuel-merkle/src/sparse/node.rs index 438a5051d0..b88d7265fe 100644 --- a/fuel-merkle/src/sparse/node.rs +++ b/fuel-merkle/src/sparse/node.rs @@ -58,7 +58,7 @@ impl Node { hash.finalize().try_into().unwrap() } - pub fn max_height() -> usize { + pub fn max_height() -> u32 { Node::key_size_in_bits() } @@ -112,7 +112,7 @@ impl Node { // leaves. // N.B.: A leaf can be a placeholder. let parent_depth = path_node.common_path_length(side_node); - let parent_height = (Node::max_height() - parent_depth) as u32; + let parent_height = Node::max_height() - parent_depth; match path.get_instruction(parent_depth).unwrap() { Instruction::Left => { Node::create_node(path_node, side_node, parent_height) @@ -127,7 +127,7 @@ impl Node { // ancestor of the node with the lesser height. // N.B.: A leaf can be a placeholder. let parent_height = cmp::max(path_node.height(), side_node.height()) + 1; - let parent_depth = Node::max_height() - parent_height as usize; + let parent_depth = Node::max_height() - parent_height; match path.get_instruction(parent_depth).unwrap() { Instruction::Left => { Node::create_node(path_node, side_node, parent_height) @@ -143,7 +143,7 @@ impl Node { Self::Placeholder } - pub fn common_path_length(&self, other: &Node) -> usize { + pub fn common_path_length(&self, other: &Node) -> u32 { debug_assert!(self.is_leaf()); debug_assert!(other.is_leaf()); diff --git a/fuel-storage/src/lib.rs b/fuel-storage/src/lib.rs index d0cfa86985..3c9fcac6e5 100644 --- a/fuel-storage/src/lib.rs +++ b/fuel-storage/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +#![deny(clippy::cast_possible_truncation)] #![deny(unsafe_code)] #![deny(unused_crate_dependencies)] diff --git a/fuel-tx/src/builder.rs b/fuel-tx/src/builder.rs index ad29b9f064..8819fccf94 100644 --- a/fuel-tx/src/builder.rs +++ b/fuel-tx/src/builder.rs @@ -172,7 +172,7 @@ impl TransactionBuilder { }; *tx.bytecode_length_mut() = (bytecode.as_ref().len() / 4) as Word; - *tx.bytecode_witness_index_mut() = tx.witnesses().len() as u8; + *tx.bytecode_witness_index_mut() = 0; tx.witnesses_mut().push(bytecode); @@ -424,7 +424,8 @@ impl TransactionBuilder { /// Adds a secret to the builder, and adds a corresponding witness if it's a new entry fn upsert_secret(&mut self, secret_key: SecretKey) -> u8 { - let witness_len = self.witnesses().len() as u8; + let witness_len = u8::try_from(self.witnesses().len()) + .expect("The number of witnesses can't exceed `u8::MAX`"); let witness_index = self.sign_keys.entry(secret_key).or_insert_with(|| { // if this private key hasn't been used before, diff --git a/fuel-tx/src/lib.rs b/fuel-tx/src/lib.rs index 66a10c230d..5c742d732d 100644 --- a/fuel-tx/src/lib.rs +++ b/fuel-tx/src/lib.rs @@ -4,6 +4,7 @@ // Wrong clippy convention; check // https://rust-lang.github.io/api-guidelines/naming.html #![allow(clippy::wrong_self_convention)] +#![deny(clippy::cast_possible_truncation)] #![deny(clippy::string_slice)] #![deny(unused_crate_dependencies)] #![deny(unsafe_code)] diff --git a/fuel-tx/src/tests/valid_cases/input.rs b/fuel-tx/src/tests/valid_cases/input.rs index d2523755af..8e52136f2a 100644 --- a/fuel-tx/src/tests/valid_cases/input.rs +++ b/fuel-tx/src/tests/valid_cases/input.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use super::PREDICATE_PARAMS; use fuel_crypto::{ diff --git a/fuel-tx/src/tests/valid_cases/transaction.rs b/fuel-tx/src/tests/valid_cases/transaction.rs index 804f7aa290..c93066b1a8 100644 --- a/fuel-tx/src/tests/valid_cases/transaction.rs +++ b/fuel-tx/src/tests/valid_cases/transaction.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use super::{ test_params, CHAIN_ID, @@ -184,7 +185,8 @@ fn max_iow() { .gas_limit(TX_PARAMS.max_gas_per_tx) .maturity(maturity); - let secrets = cmp::min(TX_PARAMS.max_inputs, TX_PARAMS.max_witnesses - 1) as usize; + let secrets = + cmp::min(TX_PARAMS.max_inputs as u32, TX_PARAMS.max_witnesses - 1) as usize; let secrets: Vec = (0..secrets - builder.inputs().len()) .map(|_| SecretKey::random(rng)) .collect(); diff --git a/fuel-tx/src/transaction/consensus_parameters.rs b/fuel-tx/src/transaction/consensus_parameters.rs index dce0f2a50c..ce293af76f 100644 --- a/fuel-tx/src/transaction/consensus_parameters.rs +++ b/fuel-tx/src/transaction/consensus_parameters.rs @@ -226,11 +226,11 @@ impl Default for PredicateParameters { #[cfg_attr(feature = "serde", serde(default))] pub struct TxParameters { /// Maximum number of inputs. - pub max_inputs: u64, + pub max_inputs: u8, /// Maximum number of outputs. - pub max_outputs: u64, + pub max_outputs: u8, /// Maximum number of witnesses. - pub max_witnesses: u64, + pub max_witnesses: u32, /// Maximum gas per transaction. pub max_gas_per_tx: u64, /// Maximum size in bytes @@ -256,19 +256,19 @@ impl TxParameters { } /// Replace the max inputs with the given argument - pub const fn with_max_inputs(mut self, max_inputs: u64) -> Self { + pub const fn with_max_inputs(mut self, max_inputs: u8) -> Self { self.max_inputs = max_inputs; self } /// Replace the max outputs with the given argument - pub const fn with_max_outputs(mut self, max_outputs: u64) -> Self { + pub const fn with_max_outputs(mut self, max_outputs: u8) -> Self { self.max_outputs = max_outputs; self } /// Replace the max witnesses with the given argument - pub const fn with_max_witnesses(mut self, max_witnesses: u64) -> Self { + pub const fn with_max_witnesses(mut self, max_witnesses: u32) -> Self { self.max_witnesses = max_witnesses; self } @@ -384,9 +384,9 @@ pub mod default_parameters { use fuel_types::ChainId; pub const CONTRACT_MAX_SIZE: u64 = ContractParameters::DEFAULT.contract_max_size; - pub const MAX_INPUTS: u64 = TxParameters::DEFAULT.max_inputs; - pub const MAX_OUTPUTS: u64 = TxParameters::DEFAULT.max_outputs; - pub const MAX_WITNESSES: u64 = TxParameters::DEFAULT.max_witnesses; + pub const MAX_INPUTS: u8 = TxParameters::DEFAULT.max_inputs; + pub const MAX_OUTPUTS: u8 = TxParameters::DEFAULT.max_outputs; + pub const MAX_WITNESSES: u32 = TxParameters::DEFAULT.max_witnesses; pub const MAX_GAS_PER_TX: u64 = TxParameters::DEFAULT.max_gas_per_tx; pub const MAX_SCRIPT_LENGTH: u64 = ScriptParameters::DEFAULT.max_script_length; diff --git a/fuel-tx/src/transaction/fee.rs b/fuel-tx/src/transaction/fee.rs index 3e116ccfa0..eca4066837 100644 --- a/fuel-tx/src/transaction/fee.rs +++ b/fuel-tx/src/transaction/fee.rs @@ -230,6 +230,7 @@ pub trait Chargeable { } #[cfg(test)] +#[allow(clippy::cast_possible_truncation)] mod tests { use crate::{ FeeParameters, diff --git a/fuel-tx/src/transaction/types/create.rs b/fuel-tx/src/transaction/types/create.rs index aca63bb8c2..f8b759f46a 100644 --- a/fuel-tx/src/transaction/types/create.rs +++ b/fuel-tx/src/transaction/types/create.rs @@ -235,7 +235,7 @@ impl FormatValidityChecks for Create { // Restrict to subset of u16::MAX, allowing this to be increased in the future // in a non-breaking way. - if self.storage_slots.len() > contract_params.max_storage_slots as usize { + if self.storage_slots.len() as u64 > contract_params.max_storage_slots { return Err(CheckError::TransactionCreateStorageSlotMax) } diff --git a/fuel-tx/src/transaction/types/output.rs b/fuel-tx/src/transaction/types/output.rs index 0aa0eb4f77..e7ff9d76c7 100644 --- a/fuel-tx/src/transaction/types/output.rs +++ b/fuel-tx/src/transaction/types/output.rs @@ -181,7 +181,11 @@ impl Output { } pub fn message_nonce(txid: &Bytes32, idx: Word) -> Nonce { - (*Hasher::default().chain(txid).chain([idx as u8]).finalize()).into() + (*Hasher::default() + .chain(txid) + .chain(idx.to_bytes()) + .finalize()) + .into() } pub fn message_digest(data: &[u8]) -> Bytes32 { diff --git a/fuel-tx/src/transaction/types/script.rs b/fuel-tx/src/transaction/types/script.rs index 9e249c5fb1..8aef166742 100644 --- a/fuel-tx/src/transaction/types/script.rs +++ b/fuel-tx/src/transaction/types/script.rs @@ -171,11 +171,11 @@ impl FormatValidityChecks for Script { consensus_params.base_asset_id(), )?; let script_params = consensus_params.script_params(); - if self.script.len() > script_params.max_script_length as usize { + if self.script.len() as u64 > script_params.max_script_length { Err(CheckError::TransactionScriptLength)?; } - if self.script_data.len() > script_params.max_script_data_length as usize { + if self.script_data.len() as u64 > script_params.max_script_data_length { Err(CheckError::TransactionScriptDataLength)?; } diff --git a/fuel-tx/src/transaction/validity.rs b/fuel-tx/src/transaction/validity.rs index f38274041c..bf7d5011f1 100644 --- a/fuel-tx/src/transaction/validity.rs +++ b/fuel-tx/src/transaction/validity.rs @@ -163,7 +163,7 @@ impl Input { Self::CoinPredicate(CoinPredicate { predicate, .. }) | Self::MessageCoinPredicate(MessageCoinPredicate { predicate, .. }) | Self::MessageDataPredicate(MessageDataPredicate { predicate, .. }) - if predicate.len() > predicate_params.max_predicate_length as usize => + if predicate.len() as u64 > predicate_params.max_predicate_length => { Err(CheckError::InputPredicateLength { index }) } @@ -174,8 +174,8 @@ impl Input { }) | Self::MessageDataPredicate(MessageDataPredicate { predicate_data, .. - }) if predicate_data.len() - > predicate_params.max_predicate_data_length as usize => + }) if predicate_data.len() as u64 + > predicate_params.max_predicate_data_length => { Err(CheckError::InputPredicateDataLength { index }) } @@ -208,7 +208,7 @@ impl Input { Self::MessageDataSigned(MessageDataSigned { data, .. }) | Self::MessageDataPredicate(MessageDataPredicate { data, .. }) if data.is_empty() - || data.len() > predicate_params.max_message_data_length as usize => + || data.len() as u64 > predicate_params.max_message_data_length => { Err(CheckError::InputMessageDataLength { index }) } diff --git a/fuel-types/src/canonical.rs b/fuel-types/src/canonical.rs index 9044618d73..60f56e2d7d 100644 --- a/fuel-types/src/canonical.rs +++ b/fuel-types/src/canonical.rs @@ -242,6 +242,7 @@ macro_rules! impl_for_primitives { impl_for_primitives!(u8, true); impl_for_primitives!(u16, false); impl_for_primitives!(u32, false); +impl_for_primitives!(usize, false); impl_for_primitives!(u64, false); impl_for_primitives!(u128, false); diff --git a/fuel-types/src/lib.rs b/fuel-types/src/lib.rs index c2c00e4e0d..bb48145a73 100644 --- a/fuel-types/src/lib.rs +++ b/fuel-types/src/lib.rs @@ -4,6 +4,7 @@ #![warn(unsafe_code)] #![warn(missing_docs)] #![deny(unused_crate_dependencies)] +#![deny(clippy::cast_possible_truncation)] // `fuel-derive` requires `fuel_types` import // TODO: Move canonical serialization to `fuel-canonical` crate #![allow(unused_crate_dependencies)] diff --git a/fuel-vm/src/call.rs b/fuel-vm/src/call.rs index 41f1bdc7fb..d2a6366fcb 100644 --- a/fuel-vm/src/call.rs +++ b/fuel-vm/src/call.rs @@ -70,7 +70,7 @@ pub struct CallFrame { to: ContractId, asset_id: AssetId, registers: [Word; VM_REGISTER_COUNT], - code_size: Word, + code_size: usize, a: Word, b: Word, } @@ -95,7 +95,7 @@ impl CallFrame { to: ContractId, asset_id: AssetId, registers: [Word; VM_REGISTER_COUNT], - code_size: Word, + code_size: usize, a: Word, b: Word, ) -> Self { @@ -155,18 +155,17 @@ impl CallFrame { } /// Contract code length in bytes. - pub fn code_size(&self) -> Word { + pub fn code_size(&self) -> usize { self.code_size } /// Padding to the next word boundary. - pub fn code_size_padding(&self) -> Word { - const WORD_SIZE: Word = crate::consts::WORD_SIZE as Word; + pub fn code_size_padding(&self) -> usize { (WORD_SIZE - self.code_size() % WORD_SIZE) % WORD_SIZE } /// Total code size including padding. - pub fn total_code_size(&self) -> Word { + pub fn total_code_size(&self) -> usize { self.code_size() + self.code_size_padding() } diff --git a/fuel-vm/src/checked_transaction.rs b/fuel-vm/src/checked_transaction.rs index 08556fd24f..ad45888196 100644 --- a/fuel-vm/src/checked_transaction.rs +++ b/fuel-vm/src/checked_transaction.rs @@ -216,7 +216,7 @@ pub struct CheckPredicateParams { /// Maximum gas per transaction pub max_gas_per_tx: u64, /// Maximum number of inputs - pub max_inputs: u64, + pub max_inputs: u8, /// Maximum size of the contract in bytes pub contract_max_size: u64, /// Maximum length of the message data @@ -617,6 +617,7 @@ impl IntoChecked for Transaction { #[cfg(feature = "random")] #[cfg(test)] mod tests { + #![allow(clippy::cast_possible_truncation)] use super::*; use alloc::vec; use fuel_asm::op; diff --git a/fuel-vm/src/consts.rs b/fuel-vm/src/consts.rs index b5c9cd8575..ee25159a5c 100644 --- a/fuel-vm/src/consts.rs +++ b/fuel-vm/src/consts.rs @@ -33,6 +33,7 @@ pub const FUEL_MAX_MEMORY_SIZE: u64 = 64; pub const VM_MAX_RAM: u64 = 1024 * 1024 * FUEL_MAX_MEMORY_SIZE; /// Size of the VM memory, in bytes. +#[allow(clippy::cast_possible_truncation)] pub const MEM_SIZE: usize = VM_MAX_RAM as usize; static_assertions::const_assert!(VM_MAX_RAM < usize::MAX as u64); diff --git a/fuel-vm/src/interpreter.rs b/fuel-vm/src/interpreter.rs index 6e44269144..41a3da99c6 100644 --- a/fuel-vm/src/interpreter.rs +++ b/fuel-vm/src/interpreter.rs @@ -135,7 +135,7 @@ pub struct InterpreterParams { /// Gas costs pub gas_costs: GasCosts, /// Maximum number of inputs - pub max_inputs: u64, + pub max_inputs: u8, /// Maximum size of the contract in bytes pub contract_max_size: u64, /// Offset of the transaction data in the memory @@ -254,7 +254,7 @@ impl Interpreter { } /// Get max_inputs value - pub fn max_inputs(&self) -> u64 { + pub fn max_inputs(&self) -> u8 { self.interpreter_params.max_inputs } diff --git a/fuel-vm/src/interpreter/alu.rs b/fuel-vm/src/interpreter/alu.rs index 3c44e99ad1..7c4e697009 100644 --- a/fuel-vm/src/interpreter/alu.rs +++ b/fuel-vm/src/interpreter/alu.rs @@ -147,7 +147,8 @@ where *common.err = 0; // set the return value to the low bits of the u128 result - *dest = (result & Word::MAX as u128) as u64; + *dest = u64::try_from(result & Word::MAX as u128) + .expect("We already truncated the result"); Ok(inc_pc(common.pc)?) } diff --git a/fuel-vm/src/interpreter/alu/muldiv.rs b/fuel-vm/src/interpreter/alu/muldiv.rs index 3f93b51272..9e72b01c57 100644 --- a/fuel-vm/src/interpreter/alu/muldiv.rs +++ b/fuel-vm/src/interpreter/alu/muldiv.rs @@ -57,12 +57,14 @@ where /// Fused multiply-divide with arbitrary precision intermediate result. /// Returns `(result, overflow)`. /// Divider 0 is treated as `1<<64`. +#[allow(clippy::cast_possible_truncation)] pub(crate) fn muldiv(lhs: u64, rhs: u64, divider: u64) -> (u64, u64) { let intermediate = lhs as u128 * rhs as u128; // Never overflows if divider == 0 { ((intermediate >> 64) as u64, 0) } else { let result = intermediate / (divider as u128); + // We want to truncate the `result` here and return a non-empty `overflow`. (result as u64, (result >> 64) as u64) } } diff --git a/fuel-vm/src/interpreter/balances.rs b/fuel-vm/src/interpreter/balances.rs index 497dc6f0a2..c256786fa2 100644 --- a/fuel-vm/src/interpreter/balances.rs +++ b/fuel-vm/src/interpreter/balances.rs @@ -164,7 +164,7 @@ impl RuntimeBalances { where Tx: ExecutableTransaction, { - let len = vm.max_inputs() * (AssetId::LEN + WORD_SIZE) as Word; + let len = (vm.max_inputs() as usize * (AssetId::LEN + WORD_SIZE)) as Word; vm.registers[RegId::SP] += len; vm.reserve_stack(len).expect( diff --git a/fuel-vm/src/interpreter/blockchain.rs b/fuel-vm/src/interpreter/blockchain.rs index 0c6d07383c..4179db7798 100644 --- a/fuel-vm/src/interpreter/blockchain.rs +++ b/fuel-vm/src/interpreter/blockchain.rs @@ -90,7 +90,9 @@ where { /// Loads contract ID pointed by `contract_id_addr`, and then for that contract, /// copies `length_unpadded` bytes from it starting from offset `contract_offset` into - /// the stack. ```txt + /// the stack. + /// + /// ```txt /// contract_id = mem[$rA, 32] /// contract_code = contracts[contract_id] /// mem[$ssp, $rC] = contract_code[$rB, $rC] @@ -500,7 +502,7 @@ where { let ssp = *self.ssp; let sp = *self.sp; - let fp = *self.fp as usize; + let fp = *self.fp; if ssp != sp { return Err(PanicReason::ExpectedUnallocatedStack.into()) @@ -514,7 +516,7 @@ where let length = bytes::padded_len_word(length_unpadded); let dst_range = MemoryRange::new(ssp, length)?; - if dst_range.end >= *self.hp as usize { + if dst_range.end as Word >= *self.hp { // Would make stack and heap overlap return Err(PanicReason::MemoryOverflow.into()) } @@ -560,9 +562,9 @@ where // Update frame pointer, if we have a stack frame (e.g. fp > 0) if fp > 0 { let fp_code_size = MemoryRange::new_overflowing_op( - usize::overflowing_add, + u64::overflowing_add, fp, - CallFrame::code_size_offset(), + CallFrame::code_size_offset() as Word, WORD_SIZE, )?; @@ -826,7 +828,7 @@ impl<'vm, S, I: Iterator> CodeSizeCtx<'vm, S, I> { self.input_contracts.check(contract_id)?; - let len = contract_size(self.storage, contract_id)?; + let len = contract_size(self.storage, contract_id)? as Word; let profiler = ProfileGas { pc: self.pc.as_ref(), is: self.is, @@ -1031,7 +1033,7 @@ struct StateReadQWord { /// The starting storage key location is stored in this range of memory. origin_key_memory_range: CheckedMemConstLen<{ Bytes32::LEN }>, /// Number of slots to read. - num_slots: Word, + num_slots: usize, } impl StateReadQWord { @@ -1041,9 +1043,11 @@ impl StateReadQWord { num_slots: Word, ownership_registers: OwnershipRegisters, ) -> SimpleResult { + let num_slots = + usize::try_from(num_slots).map_err(|_| PanicReason::ArithmeticOverflow)?; let destination_address_memory_range = MemoryRange::new( destination_memory_address, - (Bytes32::LEN as Word).saturating_mul(num_slots), + Bytes32::LEN.saturating_mul(num_slots), )?; ownership_registers.verify_ownership(&destination_address_memory_range)?; ownership_registers.verify_internal_context()?; @@ -1152,7 +1156,7 @@ struct StateClearQWord { /// in this range of memory. start_storage_key_memory_range: CheckedMemConstLen<{ Bytes32::LEN }>, /// Number of slots to read. - num_slots: Word, + num_slots: usize, } impl StateClearQWord { @@ -1163,6 +1167,8 @@ impl StateClearQWord { let start_storage_key_memory_range = CheckedMemConstLen::<{ Bytes32::LEN }>::new( start_storage_key_memory_address, )?; + let num_slots = + usize::try_from(num_slots).map_err(|_| PanicReason::ArithmeticOverflow)?; Ok(Self { start_storage_key_memory_range, num_slots, diff --git a/fuel-vm/src/interpreter/blockchain/code_tests.rs b/fuel-vm/src/interpreter/blockchain/code_tests.rs index fa8a23104a..7145706531 100644 --- a/fuel-vm/src/interpreter/blockchain/code_tests.rs +++ b/fuel-vm/src/interpreter/blockchain/code_tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use core::convert::Infallible; use alloc::vec; diff --git a/fuel-vm/src/interpreter/blockchain/test.rs b/fuel-vm/src/interpreter/blockchain/test.rs index ad5881d75e..baec2d3623 100644 --- a/fuel-vm/src/interpreter/blockchain/test.rs +++ b/fuel-vm/src/interpreter/blockchain/test.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use alloc::{ vec, vec::Vec, diff --git a/fuel-vm/src/interpreter/contract.rs b/fuel-vm/src/interpreter/contract.rs index f7b841e24a..0186cefffc 100644 --- a/fuel-vm/src/interpreter/contract.rs +++ b/fuel-vm/src/interpreter/contract.rs @@ -290,7 +290,8 @@ impl<'vm, S, Tx> TransferCtx<'vm, S, Tx> { Tx: ExecutableTransaction, S: ContractsAssetsStorage, { - let out_idx = output_index as usize; + let out_idx = + usize::try_from(output_index).map_err(|_| PanicReason::ArithmeticOverflow)?; let to = Address::from(read_bytes(self.memory, recipient_offset)?); let asset_id = AssetId::from(read_bytes(self.memory, asset_id_offset)?); let amount = transfer_amount; @@ -348,14 +349,14 @@ impl<'vm, S, Tx> TransferCtx<'vm, S, Tx> { pub(crate) fn contract_size( storage: &S, contract: &ContractId, -) -> IoResult +) -> IoResult where S: StorageSize + ?Sized, { Ok(storage .size_of_value(contract) .map_err(RuntimeError::Storage)? - .ok_or(PanicReason::ContractNotFound)? as Word) + .ok_or(PanicReason::ContractNotFound)?) } pub(crate) fn balance( diff --git a/fuel-vm/src/interpreter/contract/tests.rs b/fuel-vm/src/interpreter/contract/tests.rs index 5dcd486390..5e23607aae 100644 --- a/fuel-vm/src/interpreter/contract/tests.rs +++ b/fuel-vm/src/interpreter/contract/tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use core::convert::Infallible; use alloc::vec; diff --git a/fuel-vm/src/interpreter/crypto/tests.rs b/fuel-vm/src/interpreter/crypto/tests.rs index 7fbd040285..247fdc291b 100644 --- a/fuel-vm/src/interpreter/crypto/tests.rs +++ b/fuel-vm/src/interpreter/crypto/tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use alloc::vec; use fuel_crypto::SecretKey; diff --git a/fuel-vm/src/interpreter/diff.rs b/fuel-vm/src/interpreter/diff.rs index f168baf6b2..070715e3e5 100644 --- a/fuel-vm/src/interpreter/diff.rs +++ b/fuel-vm/src/interpreter/diff.rs @@ -202,8 +202,10 @@ where T: 'static + core::cmp::PartialEq + Clone, I: Iterator + 'iter, { - a.enumerate().zip(b).filter_map(move |(a, b)| { - (a.1 != b).then(|| { + a.enumerate() + .zip(b) + .filter(|&(a, b)| (a.1 != b)) + .map(move |(a, b)| { change(Delta { from: VecState { index: a.0, @@ -215,7 +217,6 @@ where }, }) }) - }) } type ChangeDeltaVariant = fn(Delta) -> Change; @@ -313,10 +314,8 @@ where .enumerate() .zip(b.map(Some).chain(core::iter::repeat(None))) .take_while(|((_, a), b)| a.is_some() || b.is_some()) - .filter_map(|((index, a), b)| { - b.map_or(true, |b| a.map_or(true, |a| a != b)) - .then(|| (index, a.cloned(), b.cloned())) - }) + .filter(|((_, a), b)| b.map_or(true, |b| a.map_or(true, |a| a != b))) + .map(|((index, a), b)| (index, a.cloned(), b.cloned())) } impl Interpreter { diff --git a/fuel-vm/src/interpreter/diff/storage.rs b/fuel-vm/src/interpreter/diff/storage.rs index 7f5d32807c..55415efaf6 100644 --- a/fuel-vm/src/interpreter/diff/storage.rs +++ b/fuel-vm/src/interpreter/diff/storage.rs @@ -417,7 +417,7 @@ where &self, id: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result>>, Self::DataError> { self.0.merkle_contract_state_range(id, start_key, range) } @@ -436,7 +436,7 @@ where &mut self, contract: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result, S::DataError> { self.0 .merkle_contract_state_remove_range(contract, start_key, range) diff --git a/fuel-vm/src/interpreter/executors/instruction.rs b/fuel-vm/src/interpreter/executors/instruction.rs index 574b8183ef..2f621affed 100644 --- a/fuel-vm/src/interpreter/executors/instruction.rs +++ b/fuel-vm/src/interpreter/executors/instruction.rs @@ -932,7 +932,7 @@ fn checked_nth_root(target: u64, nth_root: u64) -> Option { return Some(1) } - let nth_root = nth_root as u32; // Never loses bits, checked above + let nth_root = u32::try_from(nth_root).expect("Never loses bits, checked above"); // Use floating point operation to get an approximation for the starting point. // This is at most off by one in either direction. @@ -942,6 +942,7 @@ fn checked_nth_root(target: u64, nth_root: u64) -> Option { #[cfg(not(feature = "std"))] let powf = libm::pow; + #[allow(clippy::cast_possible_truncation)] let guess = powf(target as f64, (nth_root as f64).recip()) as u64; debug_assert!(guess != 0, "This should never occur for {{target, n}} > 1"); diff --git a/fuel-vm/src/interpreter/executors/instruction/tests.rs b/fuel-vm/src/interpreter/executors/instruction/tests.rs index 48d93f9803..288808746e 100644 --- a/fuel-vm/src/interpreter/executors/instruction/tests.rs +++ b/fuel-vm/src/interpreter/executors/instruction/tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use super::*; use fuel_asm::{ op, diff --git a/fuel-vm/src/interpreter/flow.rs b/fuel-vm/src/interpreter/flow.rs index 74f6115e0c..03509b3b73 100644 --- a/fuel-vm/src/interpreter/flow.rs +++ b/fuel-vm/src/interpreter/flow.rs @@ -523,7 +523,7 @@ where self.registers.system_registers.ggas.as_mut(), profiler, self.gas_cost, - frame.total_code_size(), + frame.total_code_size() as Word, )?; if let Some(source_contract) = self.current_contract { @@ -568,7 +568,7 @@ where let frame_bytes = frame.to_bytes(); let len = (frame_bytes.len() as Word) - .checked_add(frame.total_code_size()) + .checked_add(frame.total_code_size() as Word) .ok_or_else(|| Bug::new(BugVariant::CodeSizeOverflow))?; if len > *self.registers.system_registers.hp @@ -648,7 +648,7 @@ where { let mut code_frame_range = code_mem_range.clone(); // Addition is safe because code size + padding is always less than len - code_frame_range.shrink_end((frame.code_size() + frame.code_size_padding()) as usize); + code_frame_range.shrink_end(frame.code_size() + frame.code_size_padding()); code_frame_range .clone() .write(memory) @@ -656,20 +656,19 @@ where let mut code_range = code_mem_range.clone(); code_range.grow_start(CallFrame::serialized_size()); - code_range.shrink_end(frame.code_size_padding() as usize); + code_range.shrink_end(frame.code_size_padding()); let bytes_read = storage .storage::() .read(frame.to(), code_range.write(memory)) .map_err(RuntimeError::Storage)? .ok_or(PanicReason::ContractNotFound)?; - if bytes_read as Word != frame.code_size() { + if bytes_read != frame.code_size() { return Err(PanicReason::ContractMismatch.into()) } if frame.code_size_padding() > 0 { let mut padding_range = code_mem_range; - padding_range - .grow_start(CallFrame::serialized_size() + frame.code_size() as usize); + padding_range.grow_start(CallFrame::serialized_size() + frame.code_size()); padding_range.write(memory).fill(0); } Ok(code_frame_range.end as Word) diff --git a/fuel-vm/src/interpreter/flow/tests.rs b/fuel-vm/src/interpreter/flow/tests.rs index 6c8f133ce9..208b80610c 100644 --- a/fuel-vm/src/interpreter/flow/tests.rs +++ b/fuel-vm/src/interpreter/flow/tests.rs @@ -442,7 +442,7 @@ fn test_write_call_to_memory( ) -> IoResult { let frame_bytes = call_frame.to_bytes(); let mut storage = MemoryStorage::new(Default::default(), Default::default()); - let code = vec![6u8; call_frame.code_size() as usize]; + let code = vec![6u8; call_frame.code_size()]; StorageAsMut::storage::(&mut storage) .insert(call_frame.to(), &code) .unwrap(); @@ -465,7 +465,7 @@ fn check_memory(result: Memory, expected: CallFrame, code: Vec) { assert_eq!(frame, expected); assert_eq!( &result[CallFrame::serialized_size() - ..(CallFrame::serialized_size() + frame.total_code_size() as usize)], + ..(CallFrame::serialized_size() + frame.total_code_size())], &code[..] ); } diff --git a/fuel-vm/src/interpreter/internal.rs b/fuel-vm/src/interpreter/internal.rs index 056d10de33..f286c80faa 100644 --- a/fuel-vm/src/interpreter/internal.rs +++ b/fuel-vm/src/interpreter/internal.rs @@ -165,10 +165,12 @@ impl Interpreter { } pub(crate) fn push_stack(&mut self, data: &[u8]) -> SimpleResult<()> { - let ssp = self.reserve_stack(data.len() as Word)?; + let old_ssp = usize::try_from(self.reserve_stack(data.len() as Word)?) + .expect("SSP couldn't be more than `usize`"); + let new_ssp = usize::try_from(self.registers[RegId::SSP]) + .expect("SSP couldn't be more than `usize`"); - self.memory[ssp as usize..self.registers[RegId::SSP] as usize] - .copy_from_slice(data); + self.memory[old_ssp..new_ssp].copy_from_slice(data); Ok(()) } diff --git a/fuel-vm/src/interpreter/memory.rs b/fuel-vm/src/interpreter/memory.rs index e553a19c85..a7ea24ac00 100644 --- a/fuel-vm/src/interpreter/memory.rs +++ b/fuel-vm/src/interpreter/memory.rs @@ -157,7 +157,7 @@ impl MemoryRange { /// defined in `r[$hp]`. Panics if the range is not within the heap space. #[cfg(test)] pub fn to_heap(self, vm: &Interpreter) -> Self { - let hp = vm.registers()[RegId::HP] as usize; + let hp = usize::try_from(vm.registers()[RegId::HP]).expect("Truncate"); let start = self.start.checked_add(hp).expect("Overflow"); let end = self.end.checked_add(hp).expect("Overflow"); if end > MEM_SIZE { @@ -457,6 +457,7 @@ pub(crate) fn load_word( Ok(inc_pc(pc)?) } +#[allow(clippy::cast_possible_truncation)] pub(crate) fn store_byte( memory: &mut [u8; MEM_SIZE], owner: OwnershipRegisters, diff --git a/fuel-vm/src/interpreter/memory/allocation_tests.rs b/fuel-vm/src/interpreter/memory/allocation_tests.rs index 72d6c59bdc..d0b273691d 100644 --- a/fuel-vm/src/interpreter/memory/allocation_tests.rs +++ b/fuel-vm/src/interpreter/memory/allocation_tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use alloc::vec; use super::*; diff --git a/fuel-vm/src/interpreter/memory/tests.rs b/fuel-vm/src/interpreter/memory/tests.rs index a2616c8dad..32522af8eb 100644 --- a/fuel-vm/src/interpreter/memory/tests.rs +++ b/fuel-vm/src/interpreter/memory/tests.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use alloc::vec; use core::ops::Range; diff --git a/fuel-vm/src/interpreter/metadata.rs b/fuel-vm/src/interpreter/metadata.rs index 10245ce8ac..a6e0144b23 100644 --- a/fuel-vm/src/interpreter/metadata.rs +++ b/fuel-vm/src/interpreter/metadata.rs @@ -145,7 +145,7 @@ impl GTFInput<'_, Tx> { where Tx: ExecutableTransaction, { - let b = b as usize; + let b = usize::try_from(b).map_err(|_| PanicReason::ArithmeticOverflow)?; let args = GTFArgs::try_from(imm)?; let tx = self.tx; let ofs = self.tx_offset; diff --git a/fuel-vm/src/lib.rs b/fuel-vm/src/lib.rs index 5f9dda13dd..e9cf200e27 100644 --- a/fuel-vm/src/lib.rs +++ b/fuel-vm/src/lib.rs @@ -5,6 +5,7 @@ #![deny(unsafe_code)] #![deny(unused_must_use)] #![deny(unused_crate_dependencies)] +#![deny(clippy::cast_possible_truncation)] #![deny(clippy::string_slice)] #[doc(hidden)] // Needed by some of the exported macros diff --git a/fuel-vm/src/profiler.rs b/fuel-vm/src/profiler.rs index 7f13e93a1b..720d3c4b60 100644 --- a/fuel-vm/src/profiler.rs +++ b/fuel-vm/src/profiler.rs @@ -102,10 +102,11 @@ impl fmt::Display for InstructionLocation { self.context .map(|contract_id| format!( "contract_id={}", - contract_id - .iter() - .map(|b| format!("{b:02x?}")) - .collect::() + contract_id.iter().fold(String::new(), |mut output, b| { + use core::fmt::Write; + let _ = write!(output, "{b:02x?}"); + output + }) ),) .unwrap_or_else(|| "script".to_string()), self.offset diff --git a/fuel-vm/src/storage/interpreter.rs b/fuel-vm/src/storage/interpreter.rs index 5c7a25b32f..48323757b3 100644 --- a/fuel-vm/src/storage/interpreter.rs +++ b/fuel-vm/src/storage/interpreter.rs @@ -191,7 +191,7 @@ pub trait InterpreterStorage: &self, id: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result>>, Self::DataError>; /// Insert a range of key-value mappings into contract storage. @@ -209,7 +209,7 @@ pub trait InterpreterStorage: &mut self, contract: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result, Self::DataError>; } @@ -287,7 +287,7 @@ where &self, id: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result>>, Self::DataError> { ::merkle_contract_state_range( self.deref(), @@ -315,7 +315,7 @@ where &mut self, contract: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result, Self::DataError> { ::merkle_contract_state_remove_range( self.deref_mut(), diff --git a/fuel-vm/src/storage/memory.rs b/fuel-vm/src/storage/memory.rs index bacdd658f1..77b66d203d 100644 --- a/fuel-vm/src/storage/memory.rs +++ b/fuel-vm/src/storage/memory.rs @@ -379,7 +379,7 @@ impl InterpreterStorage for MemoryStorage { &self, id: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result>>, Self::DataError> { let start: ContractsStateKey = (id, start_key).into(); let end: ContractsStateKey = (id, &Bytes32::new([u8::MAX; 32])).into(); @@ -408,7 +408,7 @@ impl InterpreterStorage for MemoryStorage { }, None => None, }) - .take(range as usize) + .take(range) .collect()) } @@ -442,7 +442,7 @@ impl InterpreterStorage for MemoryStorage { &mut self, contract: &ContractId, start_key: &Bytes32, - range: Word, + range: usize, ) -> Result, Self::DataError> { let mut all_set_key = true; let mut values: hashbrown::HashSet<_> = @@ -454,7 +454,7 @@ impl InterpreterStorage for MemoryStorage { Some(n) } }) - .take(range as usize) + .take(range) .collect(); self.memory.contract_state.retain(|key, _| { let c = key.contract_id(); @@ -503,7 +503,7 @@ mod tests { fn test_contract_state_range( store: &[&[u8; 32]], start: &[u8; 32], - range: Word, + range: usize, ) -> Vec> { let mut mem = MemoryStorage::default(); for k in store { diff --git a/fuel-vm/src/storage/predicate.rs b/fuel-vm/src/storage/predicate.rs index a8a267ea29..43b9c92c33 100644 --- a/fuel-vm/src/storage/predicate.rs +++ b/fuel-vm/src/storage/predicate.rs @@ -150,7 +150,7 @@ impl InterpreterStorage for PredicateStorage { &self, _id: &ContractId, _start_key: &Bytes32, - _range: Word, + _range: usize, ) -> Result>>, StorageUnavailable> { Err(StorageUnavailable) } @@ -168,7 +168,7 @@ impl InterpreterStorage for PredicateStorage { &mut self, _contract: &ContractId, _start_key: &Bytes32, - _range: Word, + _range: usize, ) -> Result, StorageUnavailable> { Err(StorageUnavailable) } diff --git a/fuel-vm/src/tests/flow.rs b/fuel-vm/src/tests/flow.rs index f3aaf02b35..e6e35fd5b7 100644 --- a/fuel-vm/src/tests/flow.rs +++ b/fuel-vm/src/tests/flow.rs @@ -203,11 +203,11 @@ fn call_frame_code_offset() { contract_id, asset_id, [0; VM_REGISTER_COUNT], - contract.as_ref().len() as Word, + contract.as_ref().len(), 0, 0, ); - let stack = frame.to_bytes().len() as Word + frame.total_code_size(); + let stack = (frame.to_bytes().len() + frame.total_code_size()) as Word; let receipts = result.receipts(); @@ -445,7 +445,7 @@ fn revert() { assert_eq!(receipts[1].rb().expect("Register value expected"), val); match receipts[3] { - Receipt::Revert { ra, .. } if ra == 1 => (), + Receipt::Revert { ra: 1, .. } => (), _ => panic!("Expected revert receipt: {:?}", receipts[3]), } } diff --git a/fuel-vm/src/tests/mod.rs b/fuel-vm/src/tests/mod.rs index fc72066fb9..1ed99daa91 100644 --- a/fuel-vm/src/tests/mod.rs +++ b/fuel-vm/src/tests/mod.rs @@ -1,3 +1,4 @@ +#![allow(clippy::cast_possible_truncation)] use futures as _; use tokio as _; use tokio_rayon as _; diff --git a/fuel-vm/src/util.rs b/fuel-vm/src/util.rs index 8d4a3edef8..cd5bfb33f9 100644 --- a/fuel-vm/src/util.rs +++ b/fuel-vm/src/util.rs @@ -251,7 +251,7 @@ pub mod test_helpers { .expect("expected contract input with matching contract id"); self.builder.add_output(Output::contract( - input_idx.0 as u8, + u8::try_from(input_idx.0).expect("The input index is more than allowed"), self.rng.gen(), self.rng.gen(), )); @@ -369,7 +369,12 @@ pub mod test_helpers { data_offset, vec![ op::movi(0x11, data_offset), - op::addi(0x12, 0x11, AssetId::LEN as Immediate12), + op::addi( + 0x12, + 0x11, + Immediate12::try_from(AssetId::LEN) + .expect("`AssetId::LEN` is 32 bytes") + ), op::bal(0x10, 0x11, 0x12), op::log(0x10, RegId::ZERO, RegId::ZERO, RegId::ZERO), op::ret(RegId::ONE),