From 150a798d32bf01a2aa00138c694c2f8ac4848835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Mei=C3=9Fner?= Date: Tue, 29 Aug 2023 20:58:53 +0200 Subject: [PATCH] Fix - Upcoming `arithmetic_side_effects` lints (#33000) * dereplicode address alignment check * Uses `checked_div` and `checked_rem` in built-in loaders. * Uses `checked_div` and `checked_rem`. * sdk: replace sub() with saturating_sub() * eliminate `String` "arithmetic" * allow arithmetic side-effects in tests and benches and on types we don't control --------- Co-authored-by: Trent Nelson --- Cargo.lock | 2 + bloom/src/bloom.rs | 9 ++- perf/src/perf_libs.rs | 8 ++- perf/src/sigverify.rs | 16 ++--- program-runtime/src/prioritization_fee.rs | 29 ++++----- programs/bpf_loader/src/lib.rs | 3 +- programs/bpf_loader/src/syscalls/cpi.rs | 15 +++-- programs/bpf_loader/src/syscalls/mem_ops.rs | 7 ++- programs/bpf_loader/src/syscalls/mod.rs | 60 +++++++++++++------ programs/loader-v4/src/lib.rs | 3 +- programs/sbf/build.rs | 7 +-- .../sbf/rust/secp256k1_recover/src/lib.rs | 1 + .../zk-token-proof/benches/verify_proofs.rs | 1 + sdk/cargo-build-sbf/Cargo.toml | 1 + sdk/cargo-build-sbf/src/main.rs | 20 +++---- sdk/cargo-test-sbf/Cargo.toml | 1 + sdk/cargo-test-sbf/src/main.rs | 20 +++---- sdk/program/src/alt_bn128.rs | 1 + sdk/program/src/program_stubs.rs | 7 +-- 19 files changed, 124 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0120d8121..b171214e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5428,6 +5428,7 @@ dependencies = [ "bzip2", "cargo_metadata", "clap 3.2.23", + "itertools", "log", "predicates", "regex", @@ -5454,6 +5455,7 @@ version = "1.17.0" dependencies = [ "cargo_metadata", "clap 3.2.23", + "itertools", "log", "solana-logger", ] diff --git a/bloom/src/bloom.rs b/bloom/src/bloom.rs index 78f985b1b..d75301f6b 100644 --- a/bloom/src/bloom.rs +++ b/bloom/src/bloom.rs @@ -101,7 +101,9 @@ impl Bloom { } } fn pos(&self, key: &T, k: u64) -> u64 { - key.hash_at_index(k).wrapping_rem(self.bits.len()) + key.hash_at_index(k) + .checked_rem(self.bits.len()) + .unwrap_or(0) } pub fn clear(&mut self) { self.bits = BitVec::new_fill(false, self.bits.len()); @@ -164,7 +166,10 @@ impl From> for AtomicBloom { impl AtomicBloom { fn pos(&self, key: &T, hash_index: u64) -> (usize, u64) { - let pos = key.hash_at_index(hash_index).wrapping_rem(self.num_bits); + let pos = key + .hash_at_index(hash_index) + .checked_rem(self.num_bits) + .unwrap_or(0); // Divide by 64 to figure out which of the // AtomicU64 bit chunks we need to modify. let index = pos.wrapping_shr(6); diff --git a/perf/src/perf_libs.rs b/perf/src/perf_libs.rs index 10a22e45f..0a2d3b118 100644 --- a/perf/src/perf_libs.rs +++ b/perf/src/perf_libs.rs @@ -140,9 +140,11 @@ fn find_cuda_home(perf_libs_path: &Path) -> Option { None } -pub fn append_to_ld_library_path(path: String) { - let ld_library_path = - path + ":" + &env::var("LD_LIBRARY_PATH").unwrap_or_else(|_| "".to_string()); +pub fn append_to_ld_library_path(mut ld_library_path: String) { + if let Ok(env_value) = env::var("LD_LIBRARY_PATH") { + ld_library_path.push(':'); + ld_library_path.push_str(&env_value); + } info!("setting ld_library_path to: {:?}", ld_library_path); env::set_var("LD_LIBRARY_PATH", ld_library_path); } diff --git a/perf/src/sigverify.rs b/perf/src/sigverify.rs index 4c62c5d16..ccccd160a 100644 --- a/perf/src/sigverify.rs +++ b/perf/src/sigverify.rs @@ -614,13 +614,15 @@ pub fn ed25519_verify( // power-of-two number around that accounting for the fact that the CPU // may be busy doing other things while being a real validator // TODO: dynamically adjust this crossover - if valid_packet_count < 64 - || 100usize - .wrapping_mul(valid_packet_count) - .wrapping_div(total_packet_count) - < 90 - { - return ed25519_verify_cpu(batches, reject_non_vote, valid_packet_count); + let maybe_valid_percentage = 100usize + .wrapping_mul(valid_packet_count) + .checked_div(total_packet_count); + let Some(valid_percentage) = maybe_valid_percentage else { + return; + }; + if valid_percentage < 90 || valid_packet_count < 64 { + ed25519_verify_cpu(batches, reject_non_vote, valid_packet_count); + return; } let (signature_offsets, pubkey_offsets, msg_start_offsets, msg_sizes, sig_lens) = diff --git a/program-runtime/src/prioritization_fee.rs b/program-runtime/src/prioritization_fee.rs index 14fe3cce6..0a0f76c8d 100644 --- a/program-runtime/src/prioritization_fee.rs +++ b/program-runtime/src/prioritization_fee.rs @@ -20,26 +20,23 @@ impl PrioritizationFeeDetails { match fee_type { // TODO: remove support of 'Deprecated' after feature remove_deprecated_request_unit_ix::id() is activated PrioritizationFeeType::Deprecated(fee) => { - let priority = if compute_unit_limit == 0 { - 0 - } else { - let micro_lamport_fee: MicroLamports = - (fee as u128).saturating_mul(MICRO_LAMPORTS_PER_LAMPORT as u128); - let priority = micro_lamport_fee.saturating_div(compute_unit_limit as u128); - u64::try_from(priority).unwrap_or(u64::MAX) - }; + let micro_lamport_fee: MicroLamports = + (fee as u128).saturating_mul(MICRO_LAMPORTS_PER_LAMPORT as u128); + let priority = micro_lamport_fee + .checked_div(compute_unit_limit as u128) + .map(|priority| u64::try_from(priority).unwrap_or(u64::MAX)) + .unwrap_or(0); Self { fee, priority } } PrioritizationFeeType::ComputeUnitPrice(cu_price) => { - let fee = { - let micro_lamport_fee: MicroLamports = - (cu_price as u128).saturating_mul(compute_unit_limit as u128); - let fee = micro_lamport_fee - .saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128) - .saturating_div(MICRO_LAMPORTS_PER_LAMPORT as u128); - u64::try_from(fee).unwrap_or(u64::MAX) - }; + let micro_lamport_fee: MicroLamports = + (cu_price as u128).saturating_mul(compute_unit_limit as u128); + let fee = micro_lamport_fee + .saturating_add(MICRO_LAMPORTS_PER_LAMPORT.saturating_sub(1) as u128) + .checked_div(MICRO_LAMPORTS_PER_LAMPORT as u128) + .and_then(|fee| u64::try_from(fee).ok()) + .unwrap_or(u64::MAX); Self { fee, diff --git a/programs/bpf_loader/src/lib.rs b/programs/bpf_loader/src/lib.rs index 8c4ab7adb..99d3f583c 100644 --- a/programs/bpf_loader/src/lib.rs +++ b/programs/bpf_loader/src/lib.rs @@ -183,7 +183,8 @@ pub fn calculate_heap_cost(heap_size: u64, heap_cost: u64, enable_rounding_fix: .saturating_add(PAGE_SIZE_KB.saturating_mul(KIBIBYTE).saturating_sub(1)); } rounded_heap_size - .saturating_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE)) + .checked_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE)) + .expect("PAGE_SIZE_KB * KIBIBYTE > 0") .saturating_sub(1) .saturating_mul(heap_cost) } diff --git a/programs/bpf_loader/src/syscalls/cpi.rs b/programs/bpf_loader/src/syscalls/cpi.rs index eea321ebd..3a690ec36 100644 --- a/programs/bpf_loader/src/syscalls/cpi.rs +++ b/programs/bpf_loader/src/syscalls/cpi.rs @@ -82,7 +82,8 @@ impl<'a> CallerAccount<'a> { consume_compute_meter( invoke_context, (data.len() as u64) - .saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit), + .checked_div(invoke_context.get_compute_budget().cpi_bytes_per_unit) + .unwrap_or(u64::MAX), )?; let translated = translate( @@ -181,7 +182,8 @@ impl<'a> CallerAccount<'a> { invoke_context, account_info .data_len - .saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit), + .checked_div(invoke_context.get_compute_budget().cpi_bytes_per_unit) + .unwrap_or(u64::MAX), )?; let bpf_account_data_direct_mapping = invoke_context @@ -333,7 +335,8 @@ impl SyscallInvokeSigned for SyscallInvokeSignedRust { consume_compute_meter( invoke_context, (ix_data_len) - .saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit), + .checked_div(invoke_context.get_compute_budget().cpi_bytes_per_unit) + .unwrap_or(u64::MAX), )?; } @@ -551,7 +554,8 @@ impl SyscallInvokeSigned for SyscallInvokeSignedC { consume_compute_meter( invoke_context, (ix_data_len) - .saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit), + .checked_div(invoke_context.get_compute_budget().cpi_bytes_per_unit) + .unwrap_or(u64::MAX), )?; } @@ -756,7 +760,8 @@ where consume_compute_meter( invoke_context, (callee_account.get_data().len() as u64) - .saturating_div(invoke_context.get_compute_budget().cpi_bytes_per_unit), + .checked_div(invoke_context.get_compute_budget().cpi_bytes_per_unit) + .unwrap_or(u64::MAX), )?; accounts.push((instruction_account.index_in_caller, None)); diff --git a/programs/bpf_loader/src/syscalls/mem_ops.rs b/programs/bpf_loader/src/syscalls/mem_ops.rs index 4f02aefe4..d8e0b0a0c 100644 --- a/programs/bpf_loader/src/syscalls/mem_ops.rs +++ b/programs/bpf_loader/src/syscalls/mem_ops.rs @@ -7,9 +7,10 @@ use { fn mem_op_consume(invoke_context: &mut InvokeContext, n: u64) -> Result<(), Error> { let compute_budget = invoke_context.get_compute_budget(); - let cost = compute_budget - .mem_op_base_cost - .max(n.saturating_div(compute_budget.cpi_bytes_per_unit)); + let cost = compute_budget.mem_op_base_cost.max( + n.checked_div(compute_budget.cpi_bytes_per_unit) + .unwrap_or(u64::MAX), + ); consume_compute_meter(invoke_context, cost) } diff --git a/programs/bpf_loader/src/syscalls/mod.rs b/programs/bpf_loader/src/syscalls/mod.rs index cc2cda985..9190fd70e 100644 --- a/programs/bpf_loader/src/syscalls/mod.rs +++ b/programs/bpf_loader/src/syscalls/mod.rs @@ -331,6 +331,13 @@ pub fn create_program_runtime_environment_v1<'a>( Ok(result) } +fn address_is_aligned(address: u64) -> bool { + (address as *mut T as usize) + .checked_rem(align_of::()) + .map(|rem| rem == 0) + .expect("T to be non-zero aligned") +} + fn translate( memory_mapping: &MemoryMapping, access_type: AccessType, @@ -348,7 +355,7 @@ fn translate_type_inner<'a, T>( ) -> Result<&'a mut T, Error> { let host_addr = translate(memory_mapping, access_type, vm_addr, size_of::() as u64)?; - if check_aligned && (host_addr as *mut T as usize).wrapping_rem(align_of::()) != 0 { + if check_aligned && !address_is_aligned::(host_addr) { return Err(SyscallError::UnalignedPointer.into()); } Ok(unsafe { &mut *(host_addr as *mut T) }) @@ -388,7 +395,7 @@ fn translate_slice_inner<'a, T>( let host_addr = translate(memory_mapping, access_type, vm_addr, total_size)?; - if check_aligned && (host_addr as *mut T as usize).wrapping_rem(align_of::()) != 0 { + if check_aligned && !address_is_aligned::(host_addr) { return Err(SyscallError::UnalignedPointer.into()); } Ok(unsafe { from_raw_parts_mut(host_addr as *mut T, len as usize) }) @@ -761,9 +768,11 @@ declare_syscall!( invoke_context.get_check_size(), )?; let cost = compute_budget.mem_op_base_cost.max( - compute_budget - .sha256_byte_cost - .saturating_mul((val.len() as u64).saturating_div(2)), + compute_budget.sha256_byte_cost.saturating_mul( + (val.len() as u64) + .checked_div(2) + .expect("div by non-zero literal"), + ), ); consume_compute_meter(invoke_context, cost)?; hasher.hash(bytes); @@ -824,9 +833,11 @@ declare_syscall!( invoke_context.get_check_size(), )?; let cost = compute_budget.mem_op_base_cost.max( - compute_budget - .sha256_byte_cost - .saturating_mul((val.len() as u64).saturating_div(2)), + compute_budget.sha256_byte_cost.saturating_mul( + (val.len() as u64) + .checked_div(2) + .expect("div by non-zero literal"), + ), ); consume_compute_meter(invoke_context, cost)?; hasher.hash(bytes); @@ -1321,9 +1332,11 @@ declare_syscall!( invoke_context.get_check_size(), )?; let cost = compute_budget.mem_op_base_cost.max( - compute_budget - .sha256_byte_cost - .saturating_mul((val.len() as u64).saturating_div(2)), + compute_budget.sha256_byte_cost.saturating_mul( + (val.len() as u64) + .checked_div(2) + .expect("div by non-zero literal"), + ), ); consume_compute_meter(invoke_context, cost)?; hasher.hash(bytes); @@ -1349,7 +1362,8 @@ declare_syscall!( let budget = invoke_context.get_compute_budget(); let cost = len - .saturating_div(budget.cpi_bytes_per_unit) + .checked_div(budget.cpi_bytes_per_unit) + .unwrap_or(u64::MAX) .saturating_add(budget.syscall_base_cost); consume_compute_meter(invoke_context, cost)?; @@ -1403,7 +1417,8 @@ declare_syscall!( if length != 0 { let cost = length .saturating_add(size_of::() as u64) - .saturating_div(budget.cpi_bytes_per_unit); + .checked_div(budget.cpi_bytes_per_unit) + .unwrap_or(u64::MAX); consume_compute_meter(invoke_context, cost)?; let return_data_result = translate_slice_mut::( @@ -1636,7 +1651,9 @@ declare_syscall!( ALT_BN128_MULTIPLICATION_OUTPUT_LEN, ), ALT_BN128_PAIRING => { - let ele_len = input_size.saturating_div(ALT_BN128_PAIRING_ELEMENT_LEN as u64); + let ele_len = input_size + .checked_div(ALT_BN128_PAIRING_ELEMENT_LEN as u64) + .expect("div by non-zero constant"); let cost = budget .alt_bn128_pairing_one_pair_cost_first .saturating_add( @@ -1732,7 +1749,8 @@ declare_syscall!( budget.syscall_base_cost.saturating_add( input_len .saturating_mul(input_len) - .saturating_div(budget.big_modular_exponentiation_cost), + .checked_div(budget.big_modular_exponentiation_cost) + .unwrap_or(u64::MAX), ), )?; @@ -2405,10 +2423,7 @@ mod tests { ); let address = result.unwrap(); assert_ne!(address, 0); - assert_eq!( - (address as *const u8 as usize).wrapping_rem(align_of::()), - 0 - ); + assert!(address_is_aligned::(address)); } aligned::(); aligned::(); @@ -4032,4 +4047,11 @@ mod tests { let size = val.len().wrapping_mul(mem::size_of::()); unsafe { slice::from_raw_parts_mut(val.as_mut_ptr().cast(), size) } } + + #[test] + fn test_address_is_aligned() { + for address in 0..std::mem::size_of::() { + assert_eq!(address_is_aligned::(address as u64), address == 0); + } + } } diff --git a/programs/loader-v4/src/lib.rs b/programs/loader-v4/src/lib.rs index 1f973c211..90a036808 100644 --- a/programs/loader-v4/src/lib.rs +++ b/programs/loader-v4/src/lib.rs @@ -107,7 +107,8 @@ fn calculate_heap_cost(heap_size: u64, heap_cost: u64) -> u64 { const PAGE_SIZE_KB: u64 = 32; heap_size .saturating_add(PAGE_SIZE_KB.saturating_mul(KIBIBYTE).saturating_sub(1)) - .saturating_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE)) + .checked_div(PAGE_SIZE_KB.saturating_mul(KIBIBYTE)) + .expect("PAGE_SIZE_KB * KIBIBYTE > 0") .saturating_sub(1) .saturating_mul(heap_cost) } diff --git a/programs/sbf/build.rs b/programs/sbf/build.rs index 007ba9bfa..409657f9e 100644 --- a/programs/sbf/build.rs +++ b/programs/sbf/build.rs @@ -42,10 +42,11 @@ fn main() { return; } + let build_profile = env::var("PROFILE").expect("`PROFILE` envvar to be set"); + let install_dir = format!("target/{build_profile}/sbf"); let sbf_c = env::var("CARGO_FEATURE_SBF_C").is_ok(); if sbf_c { - let install_dir = "OUT_DIR=../target/".to_string() + &env::var("PROFILE").unwrap() + "/sbf"; - + let install_dir = format!("OUT_DIR=../{install_dir}"); println!("cargo:warning=(not a warning) Building C-based on-chain programs"); assert!(Command::new("make") .current_dir("c") @@ -60,8 +61,6 @@ fn main() { let sbf_rust = env::var("CARGO_FEATURE_SBF_RUST").is_ok(); if sbf_rust { - let install_dir = "target/".to_string() + &env::var("PROFILE").unwrap() + "/sbf"; - let rust_programs = [ "128bit", "alloc", diff --git a/programs/sbf/rust/secp256k1_recover/src/lib.rs b/programs/sbf/rust/secp256k1_recover/src/lib.rs index 10253519e..c954dda41 100644 --- a/programs/sbf/rust/secp256k1_recover/src/lib.rs +++ b/programs/sbf/rust/secp256k1_recover/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] //! Secp256k1Recover Syscall test extern crate solana_program; diff --git a/programs/zk-token-proof/benches/verify_proofs.rs b/programs/zk-token-proof/benches/verify_proofs.rs index 65ae5f9aa..2fa1e66d8 100644 --- a/programs/zk-token-proof/benches/verify_proofs.rs +++ b/programs/zk-token-proof/benches/verify_proofs.rs @@ -1,3 +1,4 @@ +#![allow(clippy::arithmetic_side_effects)] use { criterion::{criterion_group, criterion_main, Criterion}, curve25519_dalek::scalar::Scalar, diff --git a/sdk/cargo-build-sbf/Cargo.toml b/sdk/cargo-build-sbf/Cargo.toml index 053889c5a..0d96c4f94 100644 --- a/sdk/cargo-build-sbf/Cargo.toml +++ b/sdk/cargo-build-sbf/Cargo.toml @@ -13,6 +13,7 @@ edition = { workspace = true } bzip2 = { workspace = true } cargo_metadata = { workspace = true } clap = { version = "3.1.5", features = ["cargo", "env"] } +itertools = { workspace = true } log = { workspace = true, features = ["std"] } regex = { workspace = true } reqwest = { workspace = true, features = ["blocking", "rustls-tls"] } diff --git a/sdk/cargo-build-sbf/src/main.rs b/sdk/cargo-build-sbf/src/main.rs index b91f82588..6dd710e06 100644 --- a/sdk/cargo-build-sbf/src/main.rs +++ b/sdk/cargo-build-sbf/src/main.rs @@ -1,6 +1,7 @@ use { bzip2::bufread::BzDecoder, clap::{crate_description, crate_name, crate_version, Arg}, + itertools::Itertools, log::*, regex::Regex, solana_download_utils::download_file, @@ -73,15 +74,15 @@ where I: IntoIterator, S: AsRef, { - let args = args.into_iter().collect::>(); - let mut msg = format!("spawn: {}", program.display()); - for arg in args.iter() { - msg = msg + &format!(" {}", arg.as_ref().to_str().unwrap_or("?")).to_string(); - } - info!("{}", msg); + let args = Vec::from_iter(args); + let msg = args + .iter() + .map(|arg| arg.as_ref().to_str().unwrap_or("?")) + .join(" "); + info!("spawn: {}", msg); let child = Command::new(program) - .args(&args) + .args(args) .stdout(Stdio::piped()) .spawn() .unwrap_or_else(|err| { @@ -105,10 +106,7 @@ where writeln!(out, "{key}=\"{value}\" \\").unwrap(); } write!(out, "{}", program.display()).unwrap(); - for arg in args.iter() { - write!(out, " {}", arg.as_ref().to_str().unwrap_or("?")).unwrap(); - } - writeln!(out).unwrap(); + writeln!(out, "{}", msg).unwrap(); out.flush().unwrap(); error!( "To rerun the failed command for debugging use {}", diff --git a/sdk/cargo-test-sbf/Cargo.toml b/sdk/cargo-test-sbf/Cargo.toml index b5926a0e2..201e90e0f 100644 --- a/sdk/cargo-test-sbf/Cargo.toml +++ b/sdk/cargo-test-sbf/Cargo.toml @@ -12,6 +12,7 @@ edition = { workspace = true } [dependencies] cargo_metadata = { workspace = true } clap = { version = "3.1.5", features = ["cargo"] } +itertools = { workspace = true } log = { workspace = true, features = ["std"] } solana-logger = { workspace = true } diff --git a/sdk/cargo-test-sbf/src/main.rs b/sdk/cargo-test-sbf/src/main.rs index 6e1a49da8..a07aa8965 100644 --- a/sdk/cargo-test-sbf/src/main.rs +++ b/sdk/cargo-test-sbf/src/main.rs @@ -1,5 +1,6 @@ use { clap::{crate_description, crate_name, crate_version, Arg}, + itertools::Itertools, log::*, std::{ env, @@ -58,15 +59,15 @@ where I: IntoIterator, S: AsRef, { - let args = args.into_iter().collect::>(); - let mut msg = format!("spawn: {}", program.display()); - for arg in args.iter() { - msg = msg + &format!(" {}", arg.as_ref().to_str().unwrap_or("?")).to_string(); - } - info!("{}", msg); + let args = Vec::from_iter(args); + let msg = args + .iter() + .map(|arg| arg.as_ref().to_str().unwrap_or("?")) + .join(" "); + info!("spawn: {}", msg); let mut child = Command::new(program) - .args(&args) + .args(args) .spawn() .unwrap_or_else(|err| { error!("Failed to execute {}: {}", program.display(), err); @@ -89,10 +90,7 @@ where writeln!(out, "{key}=\"{value}\" \\").unwrap(); } write!(out, "{}", program.display()).unwrap(); - for arg in args.iter() { - write!(out, " {}", arg.as_ref().to_str().unwrap_or("?")).unwrap(); - } - writeln!(out).unwrap(); + writeln!(out, "{}", msg).unwrap(); out.flush().unwrap(); error!( "To rerun the failed command for debugging use {}", diff --git a/sdk/program/src/alt_bn128.rs b/sdk/program/src/alt_bn128.rs index 0020c3882..52ebd8762 100644 --- a/sdk/program/src/alt_bn128.rs +++ b/sdk/program/src/alt_bn128.rs @@ -176,6 +176,7 @@ mod target_arch { ) .try_into()?; + #[allow(clippy::arithmetic_side_effects)] let result_point = p + q; let mut result_point_data = [0u8; ALT_BN128_ADDITION_OUTPUT_LEN]; diff --git a/sdk/program/src/program_stubs.rs b/sdk/program/src/program_stubs.rs index a61b2e158..fb6861b74 100644 --- a/sdk/program/src/program_stubs.rs +++ b/sdk/program/src/program_stubs.rs @@ -223,15 +223,14 @@ pub(crate) fn sol_get_epoch_rewards_sysvar(var_addr: *mut u8) -> u64 { #[doc(hidden)] pub fn is_nonoverlapping(src: N, src_len: N, dst: N, dst_len: N) -> bool where - N: Ord + std::ops::Sub, - ::Output: Ord, + N: Ord + num_traits::SaturatingSub, { // If the absolute distance between the ptrs is at least as big as the size of the other, // they do not overlap. if src > dst { - src - dst >= dst_len + src.saturating_sub(&dst) >= dst_len } else { - dst - src >= src_len + dst.saturating_sub(&src) >= src_len } }