Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clippy check for overflowing arithmetic, fix existing cases #1274

Closed
wants to merge 8 commits into from
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,6 @@ fuels-core = { version = "0.55.0", path = "./packages/fuels-core", default-featu
fuels-macros = { version = "0.55.0", path = "./packages/fuels-macros", default-features = false }
fuels-programs = { version = "0.55.0", path = "./packages/fuels-programs", default-features = false }
fuels-test-helpers = { version = "0.55.0", path = "./packages/fuels-test-helpers", default-features = false }

[workspace.lints.clippy]
arithmetic_side_effects = "deny"
3 changes: 3 additions & 0 deletions examples/codec/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ description = "Fuel Rust SDK codec examples."
[dev-dependencies]
fuels = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ tokio = { workspace = true, features = ["full"] }
[features]
fuel-core-lib = ["fuels/fuel-core-lib"]
rocksdb = ["fuels/rocksdb"]

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/cookbook/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ tokio = { workspace = true, features = ["full"] }
[features]
rocksdb = ["fuels/rocksdb"]
fuel-core-lib = ["fuels/fuel-core-lib"]

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/debugging/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ fuels = { workspace = true }
rand = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ description = "Fuel Rust SDK macro examples."
[dev-dependencies]
fuels = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/predicates/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ description = "Fuel Rust SDK predicate examples."
fuels = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/providers/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ description = "Fuel Rust SDK provider examples."
fuels = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/rust_bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ fuels-macros = { workspace = true }
proc-macro2 = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ description = "Fuel Rust SDK types examples."
fuels = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions examples/wallets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ description = "Fuel Rust SDK wallet examples."
fuels = { workspace = true }
rand = { workspace = true }
tokio = { workspace = true, features = ["full"] }

[lints]
workspace = true
3 changes: 3 additions & 0 deletions packages/fuels-accounts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ tokio = { workspace = true, features = ["test-util"] }
default = ["std"]
coin-cache = ["tokio?/time"]
std = ["fuels-core/std", "dep:tokio", "fuel-core-client/default", "dep:eth-keystore"]

[lints]
workspace = true
20 changes: 18 additions & 2 deletions packages/fuels-accounts/src/accounts_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,25 @@ pub async fn calculate_missing_base_amount(

let available_amount = available_base_amount(tb);

let total_used = transaction_fee.max_fee() + used_base_amount;
let total_used = transaction_fee
.max_fee()
.checked_add(used_base_amount)
.ok_or_else(|| {
error!(
InvalidType,
"Addition overflow while calculating total_used for max_fee {:?} and used_base_amount {used_base_amount:?}",
transaction_fee.max_fee()
)
})?;

let missing_amount = if total_used > available_amount {
total_used - available_amount
total_used.checked_sub(available_amount)
.ok_or_else(|| {
error!(
InvalidType,
"Subtraction overflow while calculating missing_amount for available_amount {available_amount:?}"
)
})?
} else if !is_consuming_utxos(tb) {
// A tx needs to have at least 1 spendable input
// Enforce a minimum required amount on the base asset if no other inputs are present
Expand Down
5 changes: 4 additions & 1 deletion packages/fuels-accounts/src/coin_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ impl CoinCacheItem {
}

pub fn is_valid(&self, ttl: Duration) -> bool {
self.created_at + ttl > Instant::now()
self.created_at
.checked_add(ttl)
.map(|instant| instant > Instant::now())
.unwrap_or(false)
}
}

Expand Down
6 changes: 3 additions & 3 deletions packages/fuels-accounts/src/predicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ impl Predicate {
}
}

pub fn with_configurables(mut self, configurables: impl Into<Configurables>) -> Self {
pub fn with_configurables(mut self, configurables: impl Into<Configurables>) -> Result<Self> {
let configurables: Configurables = configurables.into();
configurables.update_constants_in(&mut self.code);
configurables.update_constants_in(&mut self.code)?;
let address = Self::calculate_address(&self.code);
self.address = address;
self
Ok(self)
}
}

Expand Down
8 changes: 6 additions & 2 deletions packages/fuels-accounts/src/provider/retry_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,12 @@ impl Default for Backoff {
impl Backoff {
pub fn wait_duration(&self, attempt: u32) -> Duration {
match self {
Backoff::Linear(base_duration) => *base_duration * (attempt + 1),
Backoff::Exponential(base_duration) => *base_duration * 2u32.pow(attempt),
Backoff::Linear(base_duration) => {
base_duration.saturating_mul(attempt.saturating_add(1))
}
Backoff::Exponential(base_duration) => {
base_duration.saturating_mul(2u32.saturating_pow(attempt))
}
Backoff::Fixed(interval) => *interval,
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/fuels-code-gen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ pretty_assertions = "1.4.0"

[package.metadata.cargo-machete]
ignored = ["Inflector"]

[lints]
workspace = true
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ pub(crate) fn script_bindings(
}

pub fn with_configurables(mut self, configurables: impl Into<::fuels::core::Configurables>)
-> Self
-> ::fuels::types::errors::Result<Self>
{
let configurables: ::fuels::core::Configurables = configurables.into();
configurables.update_constants_in(&mut self.binary);
self
configurables.update_constants_in(&mut self.binary)?;
::core::result::Result::Ok(self)
}

pub fn log_decoder(&self) -> ::fuels::core::codec::LogDecoder {
Expand Down
3 changes: 3 additions & 0 deletions packages/fuels-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ tokio = { workspace = true, features = ["test-util"] }
[features]
default = ["std"]
std = ["dep:fuel-core-client"]

[lints]
workspace = true
8 changes: 4 additions & 4 deletions packages/fuels-core/src/codec/abi_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -799,7 +799,7 @@ mod tests {
let fields = if depth == 1 {
vec![]
} else {
vec![nested_struct(depth - 1)]
vec![nested_struct(depth.saturating_sub(1))]
};

ParamType::Struct {
Expand All @@ -812,7 +812,7 @@ mod tests {
let fields = if depth == 1 {
vec![ParamType::U8]
} else {
vec![nested_enum(depth - 1)]
vec![nested_enum(depth.saturating_sub(1))]
};

ParamType::Enum {
Expand All @@ -825,7 +825,7 @@ mod tests {
let field = if depth == 1 {
ParamType::U8
} else {
nested_array(depth - 1)
nested_array(depth.saturating_sub(1))
};

ParamType::Array(Box::new(field), 1)
Expand All @@ -835,7 +835,7 @@ mod tests {
let fields = if depth == 1 {
vec![ParamType::U8]
} else {
vec![nested_tuple(depth - 1)]
vec![nested_tuple(depth.saturating_sub(1))]
};

ParamType::Tuple(fields)
Expand Down
39 changes: 32 additions & 7 deletions packages/fuels-core/src/codec/abi_decoder/bounded_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,12 @@ impl BoundedDecoder {
// padding has to be taken into account
bytes_read = checked_round_up_to_word_alignment(bytes_read)?;
let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?;
bytes_read += res.bytes_read;
bytes_read = bytes_read
.checked_add(res.bytes_read)
.ok_or_else(|| error!(
InvalidType,
"Addition overflow while calculating bytes_read for tuple with param_types {param_types:?}"
))?;
tokens.push(res.token);
}

Expand All @@ -171,7 +176,12 @@ impl BoundedDecoder {
// padding has to be taken into account
bytes_read = checked_round_up_to_word_alignment(bytes_read)?;
let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?;
bytes_read += res.bytes_read;
bytes_read = bytes_read
.checked_add(res.bytes_read)
.ok_or_else(|| error!(
InvalidType,
"Addition overflow while calculating bytes_read for struct with param_types {param_types:?}"
))?;
tokens.push(res.token);
}

Expand All @@ -192,7 +202,12 @@ impl BoundedDecoder {

for param_type in param_types {
let res = self.decode_param(param_type, skip(bytes, bytes_read)?)?;
bytes_read += res.bytes_read;
bytes_read = bytes_read
.checked_add(res.bytes_read)
.ok_or_else(|| error!(
InvalidType,
"Addition overflow while calculating bytes_read for param_types iterator, param_type {param_type:?}"
))?;
results.push(res.token);
}

Expand Down Expand Up @@ -332,8 +347,18 @@ impl BoundedDecoder {
_ => 0,
};

let bytes_to_skip = enum_width_in_bytes - selected_variant.compute_encoding_in_bytes()?
+ skip_extra_in_bytes;
let bytes_to_skip =
enum_width_in_bytes
.checked_sub(selected_variant.compute_encoding_in_bytes()?)
.ok_or_else(|| error!(
InvalidType,
"Subtraction overflow while calculating bytes_to_skip for enum variant {selected_variant:?}"
))?
.checked_add(skip_extra_in_bytes)
.ok_or_else(|| error!(
InvalidType,
"Addition overflow while calculating bytes_to_skip for enum variant {selected_variant:?}"
))?;

let enum_content_bytes = skip(bytes, bytes_to_skip)?;
let result = self.decode_token_in_enum(enum_content_bytes, variants, selected_variant)?;
Expand Down Expand Up @@ -386,7 +411,7 @@ impl CounterWithLimit {
}

fn increase(&mut self) -> Result<()> {
self.count += 1;
self.count = self.count.saturating_add(1);
if self.count > self.max {
Err(error!(
InvalidType,
Expand All @@ -399,7 +424,7 @@ impl CounterWithLimit {

fn decrease(&mut self) {
if self.count > 0 {
self.count -= 1;
self.count = self.count.saturating_sub(1);
}
}
}
Expand Down
29 changes: 24 additions & 5 deletions packages/fuels-core/src/codec/abi_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use fuel_types::bytes::padded_len_usize;
use crate::{
checked_round_up_to_word_alignment,
types::{
errors::Result,
errors::{error, Result},
pad_u16, pad_u32,
unresolved_bytes::{Data, UnresolvedBytes},
EnumSelector, StaticStringToken, Token, U256,
Expand Down Expand Up @@ -39,23 +39,42 @@ impl ABIEncoder {
}

fn encode_tokens(tokens: &[Token], word_aligned: bool) -> Result<Vec<Data>> {
let mut offset_in_bytes = 0;
let mut offset_in_bytes = 0usize;
let mut data = vec![];

for token in tokens.iter() {
let mut new_data = Self::encode_token(token)?;
offset_in_bytes += new_data.iter().map(|x| x.size_in_bytes()).sum::<usize>();
let new_data_size = new_data
.iter()
.map(Data::size_in_bytes)
.try_fold(0, usize::checked_add)
.ok_or_else(|| error!(InvalidType, "Addition overflow while calculating offset"))?;
offset_in_bytes = offset_in_bytes
.checked_add(new_data_size)
.ok_or_else(|| error!(InvalidType, "Addition overflow while calculating offset"))?;

data.append(&mut new_data);

if word_aligned {
let padding = vec![
0u8;
checked_round_up_to_word_alignment(offset_in_bytes)?
- offset_in_bytes
.checked_sub(offset_in_bytes)
.ok_or_else(|| {
error!(
InvalidType,
"Subtraction overflow while calculating padding"
)
})?
];
if !padding.is_empty() {
offset_in_bytes += padding.len();
offset_in_bytes =
offset_in_bytes.checked_add(padding.len()).ok_or_else(|| {
error!(
InvalidType,
"Addition overflow while calculating word-aligned offset"
)
})?;
data.push(Data::Inline(padding));
}
}
Expand Down
12 changes: 9 additions & 3 deletions packages/fuels-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod utils;

pub use utils::*;

use crate::types::errors::Result;

#[derive(Debug, Clone, Default)]
pub struct Configurables {
offsets_with_data: Vec<(u64, Vec<u8>)>,
Expand All @@ -15,10 +17,14 @@ impl Configurables {
Self { offsets_with_data }
}

pub fn update_constants_in(&self, binary: &mut [u8]) {
pub fn update_constants_in(&self, binary: &mut [u8]) -> Result<()> {
for (offset, data) in &self.offsets_with_data {
let offset = *offset as usize;
binary[offset..offset + data.len()].copy_from_slice(data)
let offset_start = *offset as usize;
let offset_end = offset_start
.checked_add(data.len())
.ok_or_else(|| error!(InvalidType, "Addition overflow while calculating offset"))?;
binary[offset_start..offset_end].copy_from_slice(data)
}
Ok(())
}
}
2 changes: 1 addition & 1 deletion packages/fuels-core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ pub fn pad_u32(value: u32) -> ByteArray {
}

pub fn pad_string(s: &str) -> Vec<u8> {
let pad = padded_len(s.as_bytes()) - s.len();
let pad = padded_len(s.as_bytes()).saturating_sub(s.len());

let mut padded = s.as_bytes().to_owned();

Expand Down
Loading