From 8820955ae72efc7bba40290f2e120302d07112f4 Mon Sep 17 00:00:00 2001 From: Joe Caulfield Date: Thu, 5 Dec 2024 11:30:00 +0900 Subject: [PATCH] sdk: evict unchecked_div_by_const --- Cargo.lock | 5 + Cargo.toml | 2 + programs/sbf/Cargo.lock | 5 + sdk/program/Cargo.toml | 1 + sdk/program/src/lib.rs | 139 +------------------------- sdk/unchecked-div-by-const/Cargo.toml | 18 ++++ sdk/unchecked-div-by-const/src/lib.rs | 136 +++++++++++++++++++++++++ svm/examples/Cargo.lock | 5 + 8 files changed, 177 insertions(+), 134 deletions(-) create mode 100644 sdk/unchecked-div-by-const/Cargo.toml create mode 100644 sdk/unchecked-div-by-const/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ab5874283bc759..2804360657fafa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7893,6 +7893,7 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-transaction-error", + "solana-unchecked-div-by-const", "static_assertions", "test-case", "thiserror 2.0.4", @@ -9512,6 +9513,10 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-unchecked-div-by-const" +version = "2.2.0" + [[package]] name = "solana-unified-scheduler-logic" version = "2.2.0" diff --git a/Cargo.toml b/Cargo.toml index c62c59226c78d2..e71d8dab3726e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,6 +179,7 @@ members = [ "sdk/transaction", "sdk/transaction-context", "sdk/transaction-error", + "sdk/unchecked-div-by-const", "send-transaction-service", "stake-accounts", "storage-bigtable", @@ -585,6 +586,7 @@ solana-transaction-metrics-tracker = { path = "transaction-metrics-tracker", ver solana-turbine = { path = "turbine", version = "=2.2.0" } solana-type-overrides = { path = "type-overrides", version = "=2.2.0" } solana-udp-client = { path = "udp-client", version = "=2.2.0" } +solana-unchecked-div-by-const = { path = "sdk/unchecked-div-by-const", version = "=2.2.0" } solana-version = { path = "version", version = "=2.2.0" } solana-vote = { path = "vote", version = "=2.2.0" } solana-vote-program = { path = "programs/vote", version = "=2.2.0" } diff --git a/programs/sbf/Cargo.lock b/programs/sbf/Cargo.lock index 4aabc16f3c955e..0005befc075820 100644 --- a/programs/sbf/Cargo.lock +++ b/programs/sbf/Cargo.lock @@ -6206,6 +6206,7 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-transaction-error", + "solana-unchecked-div-by-const", "thiserror 2.0.4", "wasm-bindgen", ] @@ -7961,6 +7962,10 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-unchecked-div-by-const" +version = "2.2.0" + [[package]] name = "solana-unified-scheduler-logic" version = "2.2.0" diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index f13f704c22a022..dbb57cff756e96 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -81,6 +81,7 @@ solana-stable-layout = { workspace = true } solana-system-interface = { workspace = true, features = ["bincode"] } solana-sysvar = { workspace = true, features = ["bincode", "bytemuck"] } solana-sysvar-id = { workspace = true } +solana-unchecked-div-by-const = { workspace = true } thiserror = { workspace = true } # This is currently needed to build on-chain programs reliably. diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index ee1561f2dfdf65..47f850504e4c27 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -622,122 +622,11 @@ extern crate serde_derive; #[cfg(feature = "frozen-abi")] extern crate solana_frozen_abi_macro; -/// Convenience macro for doing integer division where the operation's safety -/// can be checked at compile-time. -/// -/// Since `unchecked_div_by_const!()` is supposed to fail at compile-time, abuse -/// doctests to cover failure modes -/// -/// # Examples -/// -/// Literal denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// let _ = unchecked_div_by_const!(10, 0); -/// # } -/// ``` -/// -/// Const denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// const D: u64 = 0; -/// let _ = unchecked_div_by_const!(10, D); -/// # } -/// ``` -/// -/// Non-const denominator fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// let d = 0; -/// let _ = unchecked_div_by_const!(10, d); -/// # } -/// ``` -/// -/// Literal denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// const N: u64 = 10; -/// let _ = unchecked_div_by_const!(N, 0); -/// # } -/// ``` -/// -/// Const denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// const N: u64 = 10; -/// const D: u64 = 0; -/// let _ = unchecked_div_by_const!(N, D); -/// # } -/// ``` -/// -/// Non-const denominator fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// # const N: u64 = 10; -/// let d = 0; -/// let _ = unchecked_div_by_const!(N, d); -/// # } -/// ``` -/// -/// Literal denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// let n = 10; -/// let _ = unchecked_div_by_const!(n, 0); -/// # } -/// ``` -/// -/// Const denominator div-by-zero fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// let n = 10; -/// const D: u64 = 0; -/// let _ = unchecked_div_by_const!(n, D); -/// # } -/// ``` -/// -/// Non-const denominator fails: -/// -/// ```compile_fail -/// # use solana_program::unchecked_div_by_const; -/// # fn main() { -/// let n = 10; -/// let d = 0; -/// let _ = unchecked_div_by_const!(n, d); -/// # } -/// ``` -#[macro_export] -macro_rules! unchecked_div_by_const { - ($num:expr, $den:expr) => {{ - // Ensure the denominator is compile-time constant - let _ = [(); ($den - $den) as usize]; - // Compile-time constant integer div-by-zero passes for some reason - // when invoked from a compilation unit other than that where this - // macro is defined. Do an explicit zero-check for now. Sorry about the - // ugly error messages! - // https://users.rust-lang.org/t/unexpected-behavior-of-compile-time-integer-div-by-zero-check-in-declarative-macro/56718 - let _ = [(); ($den as usize) - 1]; - #[allow(clippy::arithmetic_side_effects)] - let quotient = $num / $den; - quotient - }}; -} +#[deprecated( + since = "2.2.0", + note = "Use `solana-unchecked-div-by-const` crate instead" +)] +pub use solana_unchecked_div_by_const::unchecked_div_by_const; // This module is purposefully listed after all other exports: because of an // interaction within rustdoc between the reexports inside this module of @@ -747,21 +636,3 @@ macro_rules! unchecked_div_by_const { // `solana_sdk`. #[cfg(not(target_os = "solana"))] pub mod example_mocks; - -#[cfg(test)] -mod tests { - use super::unchecked_div_by_const; - - #[test] - fn test_unchecked_div_by_const() { - const D: u64 = 2; - const N: u64 = 10; - let n = 10; - assert_eq!(unchecked_div_by_const!(10, 2), 5); - assert_eq!(unchecked_div_by_const!(N, 2), 5); - assert_eq!(unchecked_div_by_const!(n, 2), 5); - assert_eq!(unchecked_div_by_const!(10, D), 5); - assert_eq!(unchecked_div_by_const!(N, D), 5); - assert_eq!(unchecked_div_by_const!(n, D), 5); - } -} diff --git a/sdk/unchecked-div-by-const/Cargo.toml b/sdk/unchecked-div-by-const/Cargo.toml new file mode 100644 index 00000000000000..f6257ecba458f0 --- /dev/null +++ b/sdk/unchecked-div-by-const/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "solana-unchecked-div-by-const" +description = "Compile-time-safe division." +documentation = "https://docs.rs/solana-rent" +version = { workspace = true } +authors = { workspace = true } +repository = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +edition = { workspace = true } + +[dependencies] + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lints] +workspace = true diff --git a/sdk/unchecked-div-by-const/src/lib.rs b/sdk/unchecked-div-by-const/src/lib.rs new file mode 100644 index 00000000000000..9d406fffd9f539 --- /dev/null +++ b/sdk/unchecked-div-by-const/src/lib.rs @@ -0,0 +1,136 @@ +//! Compile-time-safe division. + +/// Convenience macro for doing integer division where the operation's safety +/// can be checked at compile-time. +/// +/// Since `unchecked_div_by_const!()` is supposed to fail at compile-time, abuse +/// doctests to cover failure modes +/// +/// # Examples +/// +/// Literal denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// let _ = unchecked_div_by_const!(10, 0); +/// # } +/// ``` +/// +/// Const denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// const D: u64 = 0; +/// let _ = unchecked_div_by_const!(10, D); +/// # } +/// ``` +/// +/// Non-const denominator fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// let d = 0; +/// let _ = unchecked_div_by_const!(10, d); +/// # } +/// ``` +/// +/// Literal denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// const N: u64 = 10; +/// let _ = unchecked_div_by_const!(N, 0); +/// # } +/// ``` +/// +/// Const denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// const N: u64 = 10; +/// const D: u64 = 0; +/// let _ = unchecked_div_by_const!(N, D); +/// # } +/// ``` +/// +/// Non-const denominator fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// # const N: u64 = 10; +/// let d = 0; +/// let _ = unchecked_div_by_const!(N, d); +/// # } +/// ``` +/// +/// Literal denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// let n = 10; +/// let _ = unchecked_div_by_const!(n, 0); +/// # } +/// ``` +/// +/// Const denominator div-by-zero fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// let n = 10; +/// const D: u64 = 0; +/// let _ = unchecked_div_by_const!(n, D); +/// # } +/// ``` +/// +/// Non-const denominator fails: +/// +/// ```compile_fail +/// # use solana_unchecked_div_by_const::unchecked_div_by_const; +/// # fn main() { +/// let n = 10; +/// let d = 0; +/// let _ = unchecked_div_by_const!(n, d); +/// # } +/// ``` +#[macro_export] +macro_rules! unchecked_div_by_const { + ($num:expr, $den:expr) => {{ + // Ensure the denominator is compile-time constant + let _ = [(); ($den - $den) as usize]; + // Compile-time constant integer div-by-zero passes for some reason + // when invoked from a compilation unit other than that where this + // macro is defined. Do an explicit zero-check for now. Sorry about the + // ugly error messages! + // https://users.rust-lang.org/t/unexpected-behavior-of-compile-time-integer-div-by-zero-check-in-declarative-macro/56718 + let _ = [(); ($den as usize) - 1]; + #[allow(clippy::arithmetic_side_effects)] + let quotient = $num / $den; + quotient + }}; +} + +#[cfg(test)] +mod tests { + use super::unchecked_div_by_const; + + #[test] + fn test_unchecked_div_by_const() { + const D: u64 = 2; + const N: u64 = 10; + let n = 10; + assert_eq!(unchecked_div_by_const!(10, 2), 5); + assert_eq!(unchecked_div_by_const!(N, 2), 5); + assert_eq!(unchecked_div_by_const!(n, 2), 5); + assert_eq!(unchecked_div_by_const!(10, D), 5); + assert_eq!(unchecked_div_by_const!(N, D), 5); + assert_eq!(unchecked_div_by_const!(n, D), 5); + } +} diff --git a/svm/examples/Cargo.lock b/svm/examples/Cargo.lock index 7bd58e61e953d3..bab7b96f7cebe0 100644 --- a/svm/examples/Cargo.lock +++ b/svm/examples/Cargo.lock @@ -6026,6 +6026,7 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-transaction-error", + "solana-unchecked-div-by-const", "thiserror 2.0.4", "wasm-bindgen", ] @@ -7306,6 +7307,10 @@ dependencies = [ "tokio", ] +[[package]] +name = "solana-unchecked-div-by-const" +version = "2.2.0" + [[package]] name = "solana-unified-scheduler-logic" version = "2.2.0"