From 44670b1d9b50576f3f6909a805d7e8d629ecf170 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Wed, 31 Jul 2024 17:11:10 -0300 Subject: [PATCH 01/18] Edit dev_dependencies for dev-dependencies --- docs/docs/detectors/12-soroban-version.md | 2 +- docs/docs/detectors/4-overflow-check.md | 7 +++---- .../vulnerabilities/12-soroban-version.md | 6 +++--- templates/test-case/Cargo.toml | 4 ++-- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 20 +++---------------- .../vulnerable-example/Cargo.toml | 20 +++---------------- .../remediated-example/Cargo.toml | 3 +-- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 2 +- .../vulnerable-example/Cargo.toml | 2 +- .../remediated-example/Cargo.toml | 16 +++++++-------- .../vulnerable-example/Cargo.toml | 16 +++++++-------- .../remediated-example/Cargo.toml | 16 +++++++-------- .../vulnerable-example/Cargo.toml | 16 +++++++-------- 82 files changed, 119 insertions(+), 149 deletions(-) diff --git a/docs/docs/detectors/12-soroban-version.md b/docs/docs/detectors/12-soroban-version.md index e2e340bc..efd7da2a 100644 --- a/docs/docs/detectors/12-soroban-version.md +++ b/docs/docs/detectors/12-soroban-version.md @@ -14,7 +14,7 @@ Using an old version of Soroban can be dangerous, as it may have bugs or securit [dependencies] soroban-sdk = { version = "=20.0.0" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } ``` diff --git a/docs/docs/detectors/4-overflow-check.md b/docs/docs/detectors/4-overflow-check.md index b744ade1..86951d08 100644 --- a/docs/docs/detectors/4-overflow-check.md +++ b/docs/docs/detectors/4-overflow-check.md @@ -10,7 +10,6 @@ Integer overflow will trigger a panic in debug builds or will wrap in release mode. Division by zero will cause a panic in either mode. In some applications one wants explicitly checked, wrapping or saturating arithmetic. - ### Example ```toml @@ -26,7 +25,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] @@ -62,7 +61,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] @@ -87,4 +86,4 @@ debug-assertions = true ### Implementation -The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/overflow-check). \ No newline at end of file +The detector's implementation can be found at [this link](https://github.com/CoinFabrik/scout-soroban/tree/main/detectors/overflow-check). diff --git a/docs/docs/vulnerabilities/12-soroban-version.md b/docs/docs/vulnerabilities/12-soroban-version.md index da149266..25a58d1a 100644 --- a/docs/docs/vulnerabilities/12-soroban-version.md +++ b/docs/docs/vulnerabilities/12-soroban-version.md @@ -17,7 +17,7 @@ Consider the following `Cargo.toml`: [dependencies] soroban-sdk = { version = "=19.0.0" } - [dev_dependencies] + [dev-dependencies] soroban-sdk = { version = "=19.0.0", features = ["testutils"] } ``` @@ -32,7 +32,7 @@ The vulnerable code example can be found [`here`](https://github.com/CoinFabrik/ // Use the latest version available. soroban-sdk = { workspace = true } - [dev_dependencies] + [dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } ``` @@ -41,4 +41,4 @@ The remediated code example can be found [`here`](https://github.com/CoinFabrik/ ## References - [Floating Pragma](https://swcregistry.io/docs/SWC-103/) -- [outdated Compiler Version](https://swcregistry.io/docs/SWC-102/) \ No newline at end of file +- [outdated Compiler Version](https://swcregistry.io/docs/SWC-102/) diff --git a/templates/test-case/Cargo.toml b/templates/test-case/Cargo.toml index 68b36988..4f5e2bca 100644 --- a/templates/test-case/Cargo.toml +++ b/templates/test-case/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { version = "=20.0.0" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] @@ -27,4 +27,4 @@ lto = true [profile.release-with-logs] inherits = "release" -debug-assertions = true \ No newline at end of file +debug-assertions = true diff --git a/test-cases/assert-violation/assert-violation-1/remediated-example/Cargo.toml b/test-cases/assert-violation/assert-violation-1/remediated-example/Cargo.toml index aabfe5cc..59fad1e1 100644 --- a/test-cases/assert-violation/assert-violation-1/remediated-example/Cargo.toml +++ b/test-cases/assert-violation/assert-violation-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/assert-violation/assert-violation-1/vulnerable-example/Cargo.toml b/test-cases/assert-violation/assert-violation-1/vulnerable-example/Cargo.toml index b3931c94..75f77e38 100644 --- a/test-cases/assert-violation/assert-violation-1/vulnerable-example/Cargo.toml +++ b/test-cases/assert-violation/assert-violation-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/Cargo.toml b/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/Cargo.toml index d5b11867..36b50a6b 100644 --- a/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/Cargo.toml +++ b/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/Cargo.toml b/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/Cargo.toml index 708b9a7f..aa9d8170 100644 --- a/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/Cargo.toml +++ b/test-cases/avoid-core-mem-forget/avoid-core-mem-forget-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml b/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml index a88a04a5..1405b414 100644 --- a/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml +++ b/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml b/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml index 10b4b428..e29166a3 100644 --- a/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml +++ b/test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/Cargo.toml index da115e12..8885629d 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/Cargo.toml index 993b2fcd..bbc78a0e 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/Cargo.toml index 62d3e70d..1b167005 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/Cargo.toml index f4f86234..3790a7f4 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/Cargo.toml index d2d4bf42..f9a4347c 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-3/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/Cargo.toml b/test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/Cargo.toml index 53955cb7..d767b9c2 100644 --- a/test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/Cargo.toml +++ b/test-cases/divide-before-multiply/divide-before-multiply-3/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/Cargo.toml index 73ad69c7..dd523254 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/Cargo.toml index 8bdaff6a..8931f7b9 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/Cargo.toml index cbe0904b..bf952193 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/Cargo.toml index 328d643c..c9389757 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/Cargo.toml index d0a065be..00e57279 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/Cargo.toml b/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/Cargo.toml index 37b1b363..09061798 100644 --- a/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/Cargo.toml +++ b/test-cases/dos-unbounded-operation/dos-unbounded-operation-3/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/remediated-example/Cargo.toml b/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/remediated-example/Cargo.toml index 6e8aa2ee..b6add2e2 100644 --- a/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/remediated-example/Cargo.toml +++ b/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/vulnerable-example/Cargo.toml b/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/vulnerable-example/Cargo.toml index b0cf5914..17a671e2 100644 --- a/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/vulnerable-example/Cargo.toml +++ b/test-cases/dos-unexpected-revert-with-vector/dos-unexpected-revert-with-vector-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/insufficiently-random-values/insufficiently-random-values-1/remediated-example/Cargo.toml b/test-cases/insufficiently-random-values/insufficiently-random-values-1/remediated-example/Cargo.toml index 30b385f4..372f0314 100644 --- a/test-cases/insufficiently-random-values/insufficiently-random-values-1/remediated-example/Cargo.toml +++ b/test-cases/insufficiently-random-values/insufficiently-random-values-1/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/insufficiently-random-values/insufficiently-random-values-1/vulnerable-example/Cargo.toml b/test-cases/insufficiently-random-values/insufficiently-random-values-1/vulnerable-example/Cargo.toml index 8ce272af..72082073 100644 --- a/test-cases/insufficiently-random-values/insufficiently-random-values-1/vulnerable-example/Cargo.toml +++ b/test-cases/insufficiently-random-values/insufficiently-random-values-1/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/Cargo.toml b/test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/Cargo.toml index 20b3cfbf..c695e832 100644 --- a/test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/Cargo.toml +++ b/test-cases/iterators-over-indexing/iterators-over-indexing-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/Cargo.toml b/test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/Cargo.toml index d03444a9..7ff5c9ba 100644 --- a/test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/Cargo.toml +++ b/test-cases/iterators-over-indexing/iterators-over-indexing-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/overflow-check/overflow-check-1/remediated-example/Cargo.toml b/test-cases/overflow-check/overflow-check-1/remediated-example/Cargo.toml index 891c0f22..a7e7c02d 100644 --- a/test-cases/overflow-check/overflow-check-1/remediated-example/Cargo.toml +++ b/test-cases/overflow-check/overflow-check-1/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { version = "=20.0.0" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] diff --git a/test-cases/overflow-check/overflow-check-1/vulnerable-example/Cargo.toml b/test-cases/overflow-check/overflow-check-1/vulnerable-example/Cargo.toml index 746527ea..b38e7396 100644 --- a/test-cases/overflow-check/overflow-check-1/vulnerable-example/Cargo.toml +++ b/test-cases/overflow-check/overflow-check-1/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { version = "=20.0.0" } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-1/remediated-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-1/remediated-example/Cargo.toml index 2930db92..a509a7e1 100644 --- a/test-cases/set-contract-storage/set-contract-storage-1/remediated-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/Cargo.toml index 48765b8c..cb945179 100644 --- a/test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-2/remediated-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-2/remediated-example/Cargo.toml index 469bce4b..cf9972e9 100644 --- a/test-cases/set-contract-storage/set-contract-storage-2/remediated-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/Cargo.toml index e588c294..778964f1 100644 --- a/test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-3/remediated-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-3/remediated-example/Cargo.toml index bde6f22d..27f877b8 100644 --- a/test-cases/set-contract-storage/set-contract-storage-3/remediated-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-3/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/Cargo.toml index 74b35b64..979457e7 100644 --- a/test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-3/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-4/remediated-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-4/remediated-example/Cargo.toml index 6a6f8e4f..d8bc3007 100644 --- a/test-cases/set-contract-storage/set-contract-storage-4/remediated-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-4/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/Cargo.toml b/test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/Cargo.toml index 2e010c67..59c47d45 100644 --- a/test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/Cargo.toml +++ b/test-cases/set-contract-storage/set-contract-storage-4/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml b/test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml index b82bc0ab..57d38b52 100644 --- a/test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml +++ b/test-cases/soroban-version/soroban-version-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml b/test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml index 9d9efe06..4e7b3fb9 100644 --- a/test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml +++ b/test-cases/soroban-version/soroban-version-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/remediated-example/Cargo.toml b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/remediated-example/Cargo.toml index 65936dfe..65cc731b 100644 --- a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/remediated-example/Cargo.toml +++ b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/vulnerable-example/Cargo.toml b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/vulnerable-example/Cargo.toml index f4dd6328..45430a49 100644 --- a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/vulnerable-example/Cargo.toml +++ b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-1/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/remediated-example/Cargo.toml b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/remediated-example/Cargo.toml index fae91814..82350199 100644 --- a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/remediated-example/Cargo.toml +++ b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/vulnerable-example/Cargo.toml b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/vulnerable-example/Cargo.toml index f3b66e08..a8441538 100644 --- a/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/vulnerable-example/Cargo.toml +++ b/test-cases/unprotected-mapping-operation/unprotected-mapping-operation-2/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/Cargo.toml b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/Cargo.toml index 4c498c24..86bf0c36 100644 --- a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/Cargo.toml +++ b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/Cargo.toml b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/Cargo.toml index 23a69ea8..3d281549 100644 --- a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/Cargo.toml +++ b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-1/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/Cargo.toml b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/Cargo.toml index e4ba18f1..f45b234e 100644 --- a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/Cargo.toml +++ b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/remediated-example/Cargo.toml @@ -8,24 +8,10 @@ version = "0.1.0" crate-type = ["cdylib"] [dependencies] -soroban-sdk = "=20.0.0" +soroban-sdk = { workspace = true } -[dev_dependencies] -soroban-sdk = { version = "=20.0.0", features = ["testutils"] } +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] - -[profile.release] -codegen-units = 1 -debug = 0 -debug-assertions = false -lto = true -opt-level = "z" -overflow-checks = true -panic = "abort" -strip = "symbols" - -[profile.release-with-logs] -debug-assertions = true -inherits = "release" diff --git a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/Cargo.toml b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/Cargo.toml index d4d5390d..58531b62 100644 --- a/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/Cargo.toml +++ b/test-cases/unprotected-update-current-contract-wasm/unprotected-update-current-contract-wasm-2/vulnerable-example/Cargo.toml @@ -8,24 +8,10 @@ version = "0.1.0" crate-type = ["cdylib"] [dependencies] -soroban-sdk = "=20.0.0" +soroban-sdk = { workspace = true } -[dev_dependencies] -soroban-sdk = { version = "=20.0.0", features = ["testutils"] } +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] - -[profile.release] -codegen-units = 1 -debug = 0 -debug-assertions = false -lto = true -opt-level = "z" -overflow-checks = true -panic = "abort" -strip = "symbols" - -[profile.release-with-logs] -debug-assertions = true -inherits = "release" diff --git a/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/remediated-example/Cargo.toml b/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/remediated-example/Cargo.toml index 6ccfb57a..e70c19a0 100644 --- a/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/remediated-example/Cargo.toml +++ b/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/remediated-example/Cargo.toml @@ -9,9 +9,8 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] - diff --git a/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/vulnerable-example/Cargo.toml b/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/vulnerable-example/Cargo.toml index faed6751..3681345f 100644 --- a/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/vulnerable-example/Cargo.toml +++ b/test-cases/unrestricted-transfer-from/unrestricted-transfer-from-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-1/remediated-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-1/remediated-example/Cargo.toml index dfd4e0d9..0e7ebf63 100644 --- a/test-cases/unsafe-expect/unsafe-expect-1/remediated-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-1/vulnerable-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-1/vulnerable-example/Cargo.toml index 6268a10d..7405854d 100644 --- a/test-cases/unsafe-expect/unsafe-expect-1/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-2/remediated-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-2/remediated-example/Cargo.toml index 74d9f3c5..ad51b084 100644 --- a/test-cases/unsafe-expect/unsafe-expect-2/remediated-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-2/vulnerable-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-2/vulnerable-example/Cargo.toml index c1025367..931400c0 100644 --- a/test-cases/unsafe-expect/unsafe-expect-2/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-3/remediated-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-3/remediated-example/Cargo.toml index 47be8699..0a3cea87 100644 --- a/test-cases/unsafe-expect/unsafe-expect-3/remediated-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-3/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-3/vulnerable-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-3/vulnerable-example/Cargo.toml index 37d22468..8d5efe1a 100644 --- a/test-cases/unsafe-expect/unsafe-expect-3/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-3/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-4/remediated-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-4/remediated-example/Cargo.toml index 610f6d0f..afc51b55 100644 --- a/test-cases/unsafe-expect/unsafe-expect-4/remediated-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-4/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-4/vulnerable-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-4/vulnerable-example/Cargo.toml index f84637e9..6769c822 100644 --- a/test-cases/unsafe-expect/unsafe-expect-4/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-4/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-5/remediated-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-5/remediated-example/Cargo.toml index 5f3f6c12..12b58fa9 100644 --- a/test-cases/unsafe-expect/unsafe-expect-5/remediated-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-5/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-expect/unsafe-expect-5/vulnerable-example/Cargo.toml b/test-cases/unsafe-expect/unsafe-expect-5/vulnerable-example/Cargo.toml index 7dd2b61c..11b84d96 100644 --- a/test-cases/unsafe-expect/unsafe-expect-5/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-expect/unsafe-expect-5/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-map-get/unsafe-map-get-1/remediated-example/Cargo.toml b/test-cases/unsafe-map-get/unsafe-map-get-1/remediated-example/Cargo.toml index c70637a3..75c99c5e 100644 --- a/test-cases/unsafe-map-get/unsafe-map-get-1/remediated-example/Cargo.toml +++ b/test-cases/unsafe-map-get/unsafe-map-get-1/remediated-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/Cargo.toml b/test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/Cargo.toml index 5c661412..da6ae429 100644 --- a/test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-map-get/unsafe-map-get-1/vulnerable-example/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/Cargo.toml index a33b76ee..0ec7d07d 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/Cargo.toml index 42f74d39..efd522fb 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/Cargo.toml index bb0d0f36..5fd2052e 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/Cargo.toml index 32ba2f01..2bb1b256 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/Cargo.toml index 52be41f1..e1d600fa 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-3/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/Cargo.toml index 6570b63c..3d61879e 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-3/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/Cargo.toml index f583d6b1..1b913f69 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-4/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/Cargo.toml index 06bbb0c3..473a4853 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-4/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/Cargo.toml index 0b51ce12..dfa84315 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-5/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/Cargo.toml index 5af85e08..916ac985 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-5/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/Cargo.toml index 32e823c1..82d8f95b 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-6/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/Cargo.toml b/test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/Cargo.toml index b09b504d..b29afba1 100644 --- a/test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/Cargo.toml +++ b/test-cases/unsafe-unwrap/unsafe-unwrap-6/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unused-return-enum/unused-return-enum-1/remediated-example/Cargo.toml b/test-cases/unused-return-enum/unused-return-enum-1/remediated-example/Cargo.toml index 80a5dec2..8446627a 100644 --- a/test-cases/unused-return-enum/unused-return-enum-1/remediated-example/Cargo.toml +++ b/test-cases/unused-return-enum/unused-return-enum-1/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/Cargo.toml b/test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/Cargo.toml index 529f902f..fd1739bd 100644 --- a/test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/Cargo.toml +++ b/test-cases/unused-return-enum/unused-return-enum-1/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unused-return-enum/unused-return-enum-2/remediated-example/Cargo.toml b/test-cases/unused-return-enum/unused-return-enum-2/remediated-example/Cargo.toml index 01337627..1dd7140f 100644 --- a/test-cases/unused-return-enum/unused-return-enum-2/remediated-example/Cargo.toml +++ b/test-cases/unused-return-enum/unused-return-enum-2/remediated-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/Cargo.toml b/test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/Cargo.toml index d0496327..a9ac9fe0 100644 --- a/test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/Cargo.toml +++ b/test-cases/unused-return-enum/unused-return-enum-2/vulnerable-example/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = { workspace = true } -[dev_dependencies] +[dev-dependencies] soroban-sdk = { workspace = true, features = ["testutils"] } [features] diff --git a/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/Cargo.toml b/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/Cargo.toml index 8d726cb7..9b4e6811 100644 --- a/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/Cargo.toml +++ b/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/remediated-example/Cargo.toml @@ -1,7 +1,7 @@ [package] +edition = "2021" name = "vec-could-be-mapping-remediated-1" version = "0.1.0" -edition = "2021" [lib] crate-type = ["cdylib"] @@ -9,22 +9,22 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] [profile.release] -opt-level = "z" -overflow-checks = true +codegen-units = 1 debug = 0 -strip = "symbols" debug-assertions = false -panic = "abort" -codegen-units = 1 lto = true +opt-level = "z" +overflow-checks = true +panic = "abort" +strip = "symbols" [profile.release-with-logs] +debug-assertions = true inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/Cargo.toml b/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/Cargo.toml index f6d61396..860c0f59 100644 --- a/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/Cargo.toml +++ b/test-cases/vec-could-be-mapping/vec-could-be-mapping-1/vulnerable-example/Cargo.toml @@ -1,7 +1,7 @@ [package] +edition = "2021" name = "vec-could-be-mapping-vulnerable-1" version = "0.1.0" -edition = "2021" [lib] crate-type = ["cdylib"] @@ -9,22 +9,22 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] [profile.release] -opt-level = "z" -overflow-checks = true +codegen-units = 1 debug = 0 -strip = "symbols" debug-assertions = false -panic = "abort" -codegen-units = 1 lto = true +opt-level = "z" +overflow-checks = true +panic = "abort" +strip = "symbols" [profile.release-with-logs] +debug-assertions = true inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/test-cases/zero-address/zero-address-1/remediated-example/Cargo.toml b/test-cases/zero-address/zero-address-1/remediated-example/Cargo.toml index 7694d9af..fc542d0e 100644 --- a/test-cases/zero-address/zero-address-1/remediated-example/Cargo.toml +++ b/test-cases/zero-address/zero-address-1/remediated-example/Cargo.toml @@ -1,7 +1,7 @@ [package] +edition = "2021" name = "zero-address-remediated-1" version = "0.1.0" -edition = "2021" [lib] crate-type = ["cdylib"] @@ -9,22 +9,22 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] [profile.release] -opt-level = "z" -overflow-checks = true +codegen-units = 1 debug = 0 -strip = "symbols" debug-assertions = false -panic = "abort" -codegen-units = 1 lto = true +opt-level = "z" +overflow-checks = true +panic = "abort" +strip = "symbols" [profile.release-with-logs] +debug-assertions = true inherits = "release" -debug-assertions = true \ No newline at end of file diff --git a/test-cases/zero-address/zero-address-1/vulnerable-example/Cargo.toml b/test-cases/zero-address/zero-address-1/vulnerable-example/Cargo.toml index 6e04a7c0..195c8b6e 100644 --- a/test-cases/zero-address/zero-address-1/vulnerable-example/Cargo.toml +++ b/test-cases/zero-address/zero-address-1/vulnerable-example/Cargo.toml @@ -1,7 +1,7 @@ [package] +edition = "2021" name = "zero-address-vulnerable-1" version = "0.1.0" -edition = "2021" [lib] crate-type = ["cdylib"] @@ -9,22 +9,22 @@ crate-type = ["cdylib"] [dependencies] soroban-sdk = "20.0.0-rc2" -[dev_dependencies] +[dev-dependencies] soroban-sdk = { version = "=20.0.0", features = ["testutils"] } [features] testutils = ["soroban-sdk/testutils"] [profile.release] -opt-level = "z" -overflow-checks = true +codegen-units = 1 debug = 0 -strip = "symbols" debug-assertions = false -panic = "abort" -codegen-units = 1 lto = true +opt-level = "z" +overflow-checks = true +panic = "abort" +strip = "symbols" [profile.release-with-logs] +debug-assertions = true inherits = "release" -debug-assertions = true \ No newline at end of file From c469ecdbda0f49e1e574644f954db490a5a48276 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Wed, 31 Jul 2024 17:11:30 -0300 Subject: [PATCH 02/18] Add detector and test-cases --- detectors/unnecessary-lint-allow/Cargo.toml | 17 ++ detectors/unnecessary-lint-allow/src/lib.rs | 216 ++++++++++++++++++ test-cases/unnecessary-lint-allow/Cargo.toml | 21 ++ .../remediated-example/Cargo.toml | 17 ++ .../remediated-example/src/lib.rs | 50 ++++ .../vulnerable-example/Cargo.toml | 17 ++ .../vulnerable-example/src/lib.rs | 55 +++++ 7 files changed, 393 insertions(+) create mode 100644 detectors/unnecessary-lint-allow/Cargo.toml create mode 100644 detectors/unnecessary-lint-allow/src/lib.rs create mode 100644 test-cases/unnecessary-lint-allow/Cargo.toml create mode 100644 test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml create mode 100644 test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs create mode 100644 test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml create mode 100644 test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs diff --git a/detectors/unnecessary-lint-allow/Cargo.toml b/detectors/unnecessary-lint-allow/Cargo.toml new file mode 100644 index 00000000..055144b4 --- /dev/null +++ b/detectors/unnecessary-lint-allow/Cargo.toml @@ -0,0 +1,17 @@ +[package] +edition = "2021" +name = "unnecessary-lint-allow" +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +clippy_utils = { workspace = true } +dylint_linting = { workspace = true } +if_chain = { workspace = true } +serde = { version = "1", features = ["derive"] } +utils = { workspace = true } + +[package.metadata.rust-analyzer] +rustc_private = true diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs new file mode 100644 index 00000000..7758ee2b --- /dev/null +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -0,0 +1,216 @@ +#![feature(rustc_private)] + +extern crate rustc_ast; +extern crate rustc_hir; +extern crate rustc_span; + +use std::collections::HashSet; + +use rustc_ast::{ + token::{Delimiter, Token, TokenKind}, + tokenstream::{TokenStream, TokenTree}, + AttrArgs, AttrKind, Attribute, +}; +use rustc_hir::{ + intravisit::{walk_expr, FnKind, Visitor}, + Body, FnDecl, +}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_span::{def_id::LocalDefId, sym, FileName, FileNameDisplayPreference, Span}; +use serde::{Deserialize, Serialize}; + +const LINT_MESSAGE: &str = "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them."; + +dylint_linting::impl_late_lint!( + pub UNNECESSARY_LINT_ALLOW, + Warn, + LINT_MESSAGE, + UnnecessaryLintAllow::default(), + { + name: "Unnecessary Lint Allow", + long_message: "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them.", + severity: "Medium", + help: "https://coinfabrik.github.io/scout-soroban/docs/detectors/unnecessary-lint-allow", + vulnerability_class: "Code Quality", + } +); + +#[derive(Default, Debug)] +struct UnnecessaryLintAllow { + findings: HashSet<AllowInfo>, +} + +impl UnnecessaryLintAllow { + pub fn collect_attribute( + &mut self, + cx: &LateContext, + attr: &Attribute, + scope: Scope, + item_span: Span, + ) { + if attr.span.from_expansion() { + return; + } + + if attr.has_name(sym::allow) { + if let AttrKind::Normal(item) = &attr.kind { + if let AttrArgs::Delimited(delimited_args) = &item.item.args { + let lint_names = extract_lint_names(&delimited_args.tokens); + for lint_name in lint_names { + self.findings.insert(AllowInfo { + lint_name, + span: SerializableSpan::from_span(cx, item_span), + scope, + }); + } + } + } + } + } +} + +fn extract_lint_names(tokens: &TokenStream) -> Vec<String> { + let mut lint_names = Vec::new(); + for tree in tokens.trees() { + match tree { + TokenTree::Token( + Token { + kind: TokenKind::Ident(ident, _), + .. + }, + _, + ) => { + lint_names.push(ident.to_string()); + } + TokenTree::Delimited(_, _, Delimiter::Parenthesis, inner_stream) => { + // Recursively process nested token streams + lint_names.extend(extract_lint_names(inner_stream)); + } + _ => {} + } + } + lint_names +} + +#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug)] +pub struct AllowInfo { + pub lint_name: String, + pub span: SerializableSpan, + pub scope: Scope, +} + +#[derive(Serialize, Debug, Deserialize, Clone, Copy, Hash, Eq, PartialEq)] +pub enum Scope { + Crate, + Enum, + Function, + Impl, + Line, + Struct, +} + +#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Debug)] +pub struct SerializableSpan { + pub file_name: String, + pub from_line: usize, + pub to_line: usize, +} + +impl SerializableSpan { + pub fn from_span(cx: &LateContext, span: Span) -> Self { + let source_map = cx.sess().source_map(); + let file = source_map.lookup_source_file(span.lo()); + let file_name = match &file.name { + FileName::Real(name) => name + .to_string_lossy(FileNameDisplayPreference::Remapped) + .into_owned(), + _ => String::from("<unknown>"), + }; + + let lo_loc = source_map.lookup_char_pos(span.lo()); + let hi_loc = source_map.lookup_char_pos(span.hi()); + + SerializableSpan { + file_name, + from_line: lo_loc.line, + to_line: hi_loc.line, + } + } +} + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { + fn check_crate_post(&mut self, _: &LateContext<'tcx>) { + for finding in &self.findings { + println!("Findings: {:?}", finding); + } + } + + fn check_crate(&mut self, cx: &LateContext<'tcx>) { + for attr in cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { + self.collect_attribute(cx, attr, Scope::Crate, attr.span); + } + } + + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) { + if item.span.from_expansion() { + return; + } + + let attrs = cx.tcx.hir().attrs(item.hir_id()); + let scope = match item.kind { + rustc_hir::ItemKind::Struct(..) => Scope::Struct, + rustc_hir::ItemKind::Enum(..) => Scope::Enum, + rustc_hir::ItemKind::Impl(..) => Scope::Impl, + _ => return, + }; + + for attr in attrs.iter() { + self.collect_attribute(cx, attr, scope, item.span); + } + } + + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + _: FnKind<'tcx>, + _: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + local_def_id: LocalDefId, + ) { + if span.from_expansion() { + return; + } + + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); + let attrs = cx.tcx.hir().attrs(hir_id); + + for attr in attrs.iter() { + self.collect_attribute(cx, attr, Scope::Function, span); + } + + // Use a visitor to check inner attributes + struct InnerAttrVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + lint: &'a mut UnnecessaryLintAllow, + } + + impl<'a, 'tcx> Visitor<'tcx> for InnerAttrVisitor<'a, 'tcx> { + fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { + let attrs = self.cx.tcx.hir().attrs(expr.hir_id); + if !attrs.is_empty() { + for attr in attrs.iter() { + self.lint + .collect_attribute(self.cx, attr, Scope::Line, expr.span); + } + } + + // Continue visiting child nodes + walk_expr(self, expr); + } + } + + let mut visitor = InnerAttrVisitor { cx, lint: self }; + walk_expr(&mut visitor, body.value); + } +} diff --git a/test-cases/unnecessary-lint-allow/Cargo.toml b/test-cases/unnecessary-lint-allow/Cargo.toml new file mode 100644 index 00000000..e0576682 --- /dev/null +++ b/test-cases/unnecessary-lint-allow/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +exclude = [".cargo", "target"] +members = ["unnecessary-lint-allow-*/*"] +resolver = "2" + +[workspace.dependencies] +soroban-sdk = { version = "=21.4.0" } + +[profile.release] +codegen-units = 1 +debug = 0 +debug-assertions = false +lto = true +opt-level = "z" +overflow-checks = true +panic = "abort" +strip = "symbols" + +[profile.release-with-logs] +debug-assertions = true +inherits = "release" diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml new file mode 100644 index 00000000..cb27925d --- /dev/null +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml @@ -0,0 +1,17 @@ + +[package] +edition = "2021" +name = "unnecessary-lint-allow-remediated-1" +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +soroban-sdk = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } + +[features] +testutils = ["soroban-sdk/testutils"] diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs new file mode 100644 index 00000000..1a231860 --- /dev/null +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs @@ -0,0 +1,50 @@ +#![no_std] + +use soroban_sdk::{contract, contracterror, contractimpl}; + +#[contract] +pub struct UnnecessaryLintAllow; + +#[contracterror] +#[derive(Copy, Clone)] +pub enum AssertError { + GreaterThan10 = 1, +} + +#[contractimpl] +impl UnnecessaryLintAllow { + pub fn assert_if_greater_than_10(value: u128) -> Result<bool, AssertError> { + if value <= 10 { + Ok(true) + } else { + Err(AssertError::GreaterThan10) + } + } +} + +#[cfg(test)] +mod tests { + use soroban_sdk::Env; + + use super::*; + #[test] + fn does_not_revert_if_greater() { + let env = Env::default(); + let contract = UnnecessaryLintAllowClient::new( + &env, + &env.register_contract(None, UnnecessaryLintAllow {}), + ); + assert!(contract.assert_if_greater_than_10(&5)); + } + + #[test] + #[should_panic(expected = "1")] // The custom error number is 1 + fn reverts_if_greater() { + let env = Env::default(); + let contract = UnnecessaryLintAllowClient::new( + &env, + &env.register_contract(None, UnnecessaryLintAllow {}), + ); + contract.assert_if_greater_than_10(&11); + } +} diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml new file mode 100644 index 00000000..d4da8d0a --- /dev/null +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml @@ -0,0 +1,17 @@ + +[package] +edition = "2021" +name = "unnecessary-lint-allow-vulnerable-1" +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +soroban-sdk = { workspace = true } + +[dev-dependencies] +soroban-sdk = { workspace = true, features = ["testutils"] } + +[features] +testutils = ["soroban-sdk/testutils"] diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs new file mode 100644 index 00000000..b7e5dd70 --- /dev/null +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs @@ -0,0 +1,55 @@ +#![no_std] +#![allow(assert_violation)] +use soroban_sdk::{contract, contracterror, contractimpl}; + +#[contract] +#[allow(assert_violation)] +pub struct UnnecessaryLintAllow; + +#[contracterror] +#[derive(Copy, Clone)] +#[allow(assert_violation)] +pub enum AssertError { + GreaterThan10 = 1, +} + +#[contractimpl] +#[allow(assert_violation)] +impl UnnecessaryLintAllow { + #[allow(assert_violation)] + pub fn assert_if_greater_than_10(value: u128) -> Result<bool, AssertError> { + if value <= 10 { + Ok(true) + } else { + #[allow(assert_violation)] + Err(AssertError::GreaterThan10) + } + } +} + +// #[cfg(test)] +// mod tests { +// use soroban_sdk::Env; + +// use super::*; +// #[test] +// fn does_not_revert_if_greater() { +// let env = Env::default(); +// let contract = UnnecessaryLintAllowClient::new( +// &env, +// &env.register_contract(None, UnnecessaryLintAllow {}), +// ); +// assert!(contract.assert_if_greater_than_10(&5)); +// } + +// #[test] +// #[should_panic(expected = "1")] // The custom error number is 1 +// fn reverts_if_greater() { +// let env = Env::default(); +// let contract = UnnecessaryLintAllowClient::new( +// &env, +// &env.register_contract(None, UnnecessaryLintAllow {}), +// ); +// contract.assert_if_greater_than_10(&11); +// } +// } From d1bf6466f3ef77f0606d08b755f2c839cdb2c6de Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Thu, 1 Aug 2024 15:39:53 -0300 Subject: [PATCH 03/18] Create a stack-like struct for extracting lint names, and add types.rs for clarity --- detectors/unnecessary-lint-allow/Cargo.toml | 1 - detectors/unnecessary-lint-allow/src/lib.rs | 148 +++++++----------- detectors/unnecessary-lint-allow/src/types.rs | 48 ++++++ 3 files changed, 106 insertions(+), 91 deletions(-) create mode 100644 detectors/unnecessary-lint-allow/src/types.rs diff --git a/detectors/unnecessary-lint-allow/Cargo.toml b/detectors/unnecessary-lint-allow/Cargo.toml index 055144b4..925700a4 100644 --- a/detectors/unnecessary-lint-allow/Cargo.toml +++ b/detectors/unnecessary-lint-allow/Cargo.toml @@ -11,7 +11,6 @@ clippy_utils = { workspace = true } dylint_linting = { workspace = true } if_chain = { workspace = true } serde = { version = "1", features = ["derive"] } -utils = { workspace = true } [package.metadata.rust-analyzer] rustc_private = true diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 7758ee2b..53e3d10e 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -4,8 +4,9 @@ extern crate rustc_ast; extern crate rustc_hir; extern crate rustc_span; -use std::collections::HashSet; +mod types; +use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, tokenstream::{TokenStream, TokenTree}, @@ -15,11 +16,12 @@ use rustc_hir::{ intravisit::{walk_expr, FnKind, Visitor}, Body, FnDecl, }; -use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_span::{def_id::LocalDefId, sym, FileName, FileNameDisplayPreference, Span}; -use serde::{Deserialize, Serialize}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_span::{def_id::LocalDefId, sym, Span}; +use std::collections::{HashSet, VecDeque}; +use types::{AllowInfo, Scope, SpanInfo}; -const LINT_MESSAGE: &str = "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them."; +const LINT_MESSAGE: &str = "This `#[allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; dylint_linting::impl_late_lint!( pub UNNECESSARY_LINT_ALLOW, @@ -29,13 +31,13 @@ dylint_linting::impl_late_lint!( { name: "Unnecessary Lint Allow", long_message: "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them.", - severity: "Medium", + severity: "Enhancement", help: "https://coinfabrik.github.io/scout-soroban/docs/detectors/unnecessary-lint-allow", vulnerability_class: "Code Quality", } ); -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] struct UnnecessaryLintAllow { findings: HashSet<AllowInfo>, } @@ -48,104 +50,69 @@ impl UnnecessaryLintAllow { scope: Scope, item_span: Span, ) { - if attr.span.from_expansion() { - return; - } - - if attr.has_name(sym::allow) { - if let AttrKind::Normal(item) = &attr.kind { - if let AttrArgs::Delimited(delimited_args) = &item.item.args { - let lint_names = extract_lint_names(&delimited_args.tokens); - for lint_name in lint_names { - self.findings.insert(AllowInfo { - lint_name, - span: SerializableSpan::from_span(cx, item_span), - scope, - }); - } + if_chain! { + if !attr.span.from_expansion(); + if attr.has_name(sym::allow); + if let AttrKind::Normal(item) = &attr.kind; + if let AttrArgs::Delimited(delimited_args) = &item.item.args; + then { + let lint_names = self.extract_lint_names(&delimited_args.tokens); + for lint_name in lint_names { + self.findings.insert(AllowInfo { + lint_name, + span: SpanInfo::from_span(cx, item_span), + scope, + }); } } } } -} -fn extract_lint_names(tokens: &TokenStream) -> Vec<String> { - let mut lint_names = Vec::new(); - for tree in tokens.trees() { - match tree { - TokenTree::Token( - Token { - kind: TokenKind::Ident(ident, _), - .. - }, - _, - ) => { - lint_names.push(ident.to_string()); - } - TokenTree::Delimited(_, _, Delimiter::Parenthesis, inner_stream) => { - // Recursively process nested token streams - lint_names.extend(extract_lint_names(inner_stream)); + pub fn extract_lint_names(&self, tokens: &TokenStream) -> Vec<String> { + let mut lint_names = Vec::new(); + let mut stack = VecDeque::new(); + stack.push_back(tokens); + + while let Some(current_stream) = stack.pop_back() { + for tree in current_stream.trees() { + match tree { + TokenTree::Token( + Token { + kind: TokenKind::Ident(ident, _), + .. + }, + _, + ) => { + lint_names.push(ident.to_string()); + } + TokenTree::Delimited(_, _, Delimiter::Parenthesis, inner_stream) => { + // Push the inner stream onto the stack for later processing + stack.push_back(inner_stream); + } + _ => {} // Ignore other token types + } } - _ => {} } - } - lint_names -} -#[derive(Serialize, Deserialize, Eq, Hash, PartialEq, Debug)] -pub struct AllowInfo { - pub lint_name: String, - pub span: SerializableSpan, - pub scope: Scope, -} - -#[derive(Serialize, Debug, Deserialize, Clone, Copy, Hash, Eq, PartialEq)] -pub enum Scope { - Crate, - Enum, - Function, - Impl, - Line, - Struct, -} - -#[derive(Serialize, Deserialize, Eq, PartialEq, Hash, Debug)] -pub struct SerializableSpan { - pub file_name: String, - pub from_line: usize, - pub to_line: usize, -} - -impl SerializableSpan { - pub fn from_span(cx: &LateContext, span: Span) -> Self { - let source_map = cx.sess().source_map(); - let file = source_map.lookup_source_file(span.lo()); - let file_name = match &file.name { - FileName::Real(name) => name - .to_string_lossy(FileNameDisplayPreference::Remapped) - .into_owned(), - _ => String::from("<unknown>"), - }; - - let lo_loc = source_map.lookup_char_pos(span.lo()); - let hi_loc = source_map.lookup_char_pos(span.hi()); - - SerializableSpan { - file_name, - from_line: lo_loc.line, - to_line: hi_loc.line, - } + lint_names } } impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { fn check_crate_post(&mut self, _: &LateContext<'tcx>) { for finding in &self.findings { - println!("Findings: {:?}", finding); + println!( + "Found unnecessary `#[allow({})]` attribute at {}:{}-{}", + finding.lint_name, + finding.span.file_name, + finding.span.from_line, + finding.span.to_line + ); } } fn check_crate(&mut self, cx: &LateContext<'tcx>) { + // Collect crate-level attributes for attr in cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { self.collect_attribute(cx, attr, Scope::Crate, attr.span); } @@ -156,6 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { return; } + // Collect item-level attributes (struct, enum, impl) let attrs = cx.tcx.hir().attrs(item.hir_id()); let scope = match item.kind { rustc_hir::ItemKind::Struct(..) => Scope::Struct, @@ -178,18 +146,19 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { span: Span, local_def_id: LocalDefId, ) { + // If the function comes from a macro expansion, we ignore it if span.from_expansion() { return; } + // Collect function level attributes (function) let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = cx.tcx.hir().attrs(hir_id); - for attr in attrs.iter() { self.collect_attribute(cx, attr, Scope::Function, span); } - // Use a visitor to check inner attributes + // Collect inner-level attributes (line) struct InnerAttrVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, lint: &'a mut UnnecessaryLintAllow, @@ -205,7 +174,6 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { } } - // Continue visiting child nodes walk_expr(self, expr); } } diff --git a/detectors/unnecessary-lint-allow/src/types.rs b/detectors/unnecessary-lint-allow/src/types.rs new file mode 100644 index 00000000..1adaf462 --- /dev/null +++ b/detectors/unnecessary-lint-allow/src/types.rs @@ -0,0 +1,48 @@ +use rustc_lint::{LateContext, LintContext}; +use rustc_span::{FileName, FileNameDisplayPreference, Span}; + +#[derive(Eq, Hash, PartialEq, Debug, Clone)] +pub struct AllowInfo { + pub lint_name: String, + pub span: SpanInfo, + pub scope: Scope, +} + +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum Scope { + Crate, + Enum, + Function, + Impl, + Line, + Struct, +} + +#[derive(Eq, PartialEq, Hash, Debug, Clone)] +pub struct SpanInfo { + pub file_name: String, + pub from_line: usize, + pub to_line: usize, +} + +impl SpanInfo { + pub fn from_span(cx: &LateContext, span: Span) -> Self { + let source_map = cx.sess().source_map(); + let file = source_map.lookup_source_file(span.lo()); + let file_name = match &file.name { + FileName::Real(name) => name + .to_string_lossy(FileNameDisplayPreference::Remapped) + .into_owned(), + _ => String::from("<unknown>"), + }; + + let lo_loc = source_map.lookup_char_pos(span.lo()); + let hi_loc = source_map.lookup_char_pos(span.hi()); + + SpanInfo { + file_name, + from_line: lo_loc.line, + to_line: hi_loc.line, + } + } +} From e29bf40ed26308f943a391b150da63c09c0e5005 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Thu, 1 Aug 2024 15:40:50 -0300 Subject: [PATCH 04/18] Remove test and excess attributes --- .../remediated-example/src/lib.rs | 27 ---------------- .../vulnerable-example/src/lib.rs | 32 ------------------- 2 files changed, 59 deletions(-) diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs index 1a231860..73fba1db 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs @@ -21,30 +21,3 @@ impl UnnecessaryLintAllow { } } } - -#[cfg(test)] -mod tests { - use soroban_sdk::Env; - - use super::*; - #[test] - fn does_not_revert_if_greater() { - let env = Env::default(); - let contract = UnnecessaryLintAllowClient::new( - &env, - &env.register_contract(None, UnnecessaryLintAllow {}), - ); - assert!(contract.assert_if_greater_than_10(&5)); - } - - #[test] - #[should_panic(expected = "1")] // The custom error number is 1 - fn reverts_if_greater() { - let env = Env::default(); - let contract = UnnecessaryLintAllowClient::new( - &env, - &env.register_contract(None, UnnecessaryLintAllow {}), - ); - contract.assert_if_greater_than_10(&11); - } -} diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs index b7e5dd70..89e06e08 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs @@ -1,14 +1,11 @@ #![no_std] -#![allow(assert_violation)] use soroban_sdk::{contract, contracterror, contractimpl}; #[contract] -#[allow(assert_violation)] pub struct UnnecessaryLintAllow; #[contracterror] #[derive(Copy, Clone)] -#[allow(assert_violation)] pub enum AssertError { GreaterThan10 = 1, } @@ -16,40 +13,11 @@ pub enum AssertError { #[contractimpl] #[allow(assert_violation)] impl UnnecessaryLintAllow { - #[allow(assert_violation)] pub fn assert_if_greater_than_10(value: u128) -> Result<bool, AssertError> { if value <= 10 { Ok(true) } else { - #[allow(assert_violation)] Err(AssertError::GreaterThan10) } } } - -// #[cfg(test)] -// mod tests { -// use soroban_sdk::Env; - -// use super::*; -// #[test] -// fn does_not_revert_if_greater() { -// let env = Env::default(); -// let contract = UnnecessaryLintAllowClient::new( -// &env, -// &env.register_contract(None, UnnecessaryLintAllow {}), -// ); -// assert!(contract.assert_if_greater_than_10(&5)); -// } - -// #[test] -// #[should_panic(expected = "1")] // The custom error number is 1 -// fn reverts_if_greater() { -// let env = Env::default(); -// let contract = UnnecessaryLintAllowClient::new( -// &env, -// &env.register_contract(None, UnnecessaryLintAllow {}), -// ); -// contract.assert_if_greater_than_10(&11); -// } -// } From 9393b13725921707ba7f01373b98f1a685df4a94 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Fri, 2 Aug 2024 12:04:04 -0300 Subject: [PATCH 05/18] Simplify scopes, improve attribute detection --- detectors/unnecessary-lint-allow/src/lib.rs | 101 +++++++++--------- detectors/unnecessary-lint-allow/src/types.rs | 6 +- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 53e3d10e..4080ed19 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -12,10 +12,7 @@ use rustc_ast::{ tokenstream::{TokenStream, TokenTree}, AttrArgs, AttrKind, Attribute, }; -use rustc_hir::{ - intravisit::{walk_expr, FnKind, Visitor}, - Body, FnDecl, -}; +use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, Item, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::{def_id::LocalDefId, sym, Span}; use std::collections::{HashSet, VecDeque}; @@ -43,7 +40,22 @@ struct UnnecessaryLintAllow { } impl UnnecessaryLintAllow { - pub fn collect_attribute( + fn check_and_collect_attrs( + &mut self, + cx: &LateContext, + hir_id: HirId, + scope: Scope, + span: Span, + ) { + let attrs = cx.tcx.hir().attrs(hir_id); + if !attrs.is_empty() { + for attr in attrs.iter() { + self.collect_attribute(cx, attr, scope, span); + } + } + } + + fn collect_attribute( &mut self, cx: &LateContext, attr: &Attribute, @@ -68,7 +80,7 @@ impl UnnecessaryLintAllow { } } - pub fn extract_lint_names(&self, tokens: &TokenStream) -> Vec<String> { + fn extract_lint_names(&self, tokens: &TokenStream) -> Vec<String> { let mut lint_names = Vec::new(); let mut stack = VecDeque::new(); stack.push_back(tokens); @@ -89,7 +101,7 @@ impl UnnecessaryLintAllow { // Push the inner stream onto the stack for later processing stack.push_back(inner_stream); } - _ => {} // Ignore other token types + _ => {} } } } @@ -102,39 +114,51 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { fn check_crate_post(&mut self, _: &LateContext<'tcx>) { for finding in &self.findings { println!( - "Found unnecessary `#[allow({})]` attribute at {}:{}-{}", + "Found unnecessary `#[allow({})]` attribute at {}:{}-{}, type: {:?}", finding.lint_name, finding.span.file_name, finding.span.from_line, - finding.span.to_line + finding.span.to_line, + finding.scope ); } } fn check_crate(&mut self, cx: &LateContext<'tcx>) { // Collect crate-level attributes - for attr in cx.tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { - self.collect_attribute(cx, attr, Scope::Crate, attr.span); - } + self.check_and_collect_attrs( + cx, + CRATE_HIR_ID, + Scope::Crate, + cx.tcx.hir().span(CRATE_HIR_ID), + ); } - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx rustc_hir::Item<'tcx>) { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { if item.span.from_expansion() { return; } // Collect item-level attributes (struct, enum, impl) - let attrs = cx.tcx.hir().attrs(item.hir_id()); - let scope = match item.kind { - rustc_hir::ItemKind::Struct(..) => Scope::Struct, - rustc_hir::ItemKind::Enum(..) => Scope::Enum, - rustc_hir::ItemKind::Impl(..) => Scope::Impl, - _ => return, - }; - - for attr in attrs.iter() { - self.collect_attribute(cx, attr, scope, item.span); + self.check_and_collect_attrs(cx, item.hir_id(), Scope::Other, item.span); + } + + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) { + if stmt.span.from_expansion() { + return; + } + + // Collect statement-level attributes (let, return, etc.) + self.check_and_collect_attrs(cx, stmt.hir_id, Scope::Other, stmt.span); + } + + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + if expr.span.from_expansion() { + return; } + + // Collect expression-level attributes (function call, etc.) + self.check_and_collect_attrs(cx, expr.hir_id, Scope::Other, expr.span); } fn check_fn( @@ -142,43 +166,16 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { cx: &LateContext<'tcx>, _: FnKind<'tcx>, _: &'tcx FnDecl<'tcx>, - body: &'tcx Body<'tcx>, + _: &'tcx Body<'tcx>, span: Span, local_def_id: LocalDefId, ) { - // If the function comes from a macro expansion, we ignore it if span.from_expansion() { return; } // Collect function level attributes (function) let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); - let attrs = cx.tcx.hir().attrs(hir_id); - for attr in attrs.iter() { - self.collect_attribute(cx, attr, Scope::Function, span); - } - - // Collect inner-level attributes (line) - struct InnerAttrVisitor<'a, 'tcx> { - cx: &'a LateContext<'tcx>, - lint: &'a mut UnnecessaryLintAllow, - } - - impl<'a, 'tcx> Visitor<'tcx> for InnerAttrVisitor<'a, 'tcx> { - fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { - let attrs = self.cx.tcx.hir().attrs(expr.hir_id); - if !attrs.is_empty() { - for attr in attrs.iter() { - self.lint - .collect_attribute(self.cx, attr, Scope::Line, expr.span); - } - } - - walk_expr(self, expr); - } - } - - let mut visitor = InnerAttrVisitor { cx, lint: self }; - walk_expr(&mut visitor, body.value); + self.check_and_collect_attrs(cx, hir_id, Scope::Other, span); } } diff --git a/detectors/unnecessary-lint-allow/src/types.rs b/detectors/unnecessary-lint-allow/src/types.rs index 1adaf462..e3838cf2 100644 --- a/detectors/unnecessary-lint-allow/src/types.rs +++ b/detectors/unnecessary-lint-allow/src/types.rs @@ -11,11 +11,7 @@ pub struct AllowInfo { #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] pub enum Scope { Crate, - Enum, - Function, - Impl, - Line, - Struct, + Other, } #[derive(Eq, PartialEq, Hash, Debug, Clone)] From a69343c9c5a0e82b4d8985b24eadbacb93487192 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Thu, 8 Aug 2024 11:12:11 -0300 Subject: [PATCH 06/18] Update detector --- detectors/unnecessary-lint-allow/src/lib.rs | 58 ++++++++----------- detectors/unnecessary-lint-allow/src/types.rs | 44 -------------- 2 files changed, 24 insertions(+), 78 deletions(-) delete mode 100644 detectors/unnecessary-lint-allow/src/types.rs diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 4080ed19..56aa1cf5 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -4,8 +4,6 @@ extern crate rustc_ast; extern crate rustc_hir; extern crate rustc_span; -mod types; - use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, @@ -16,7 +14,6 @@ use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, Item, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::{def_id::LocalDefId, sym, Span}; use std::collections::{HashSet, VecDeque}; -use types::{AllowInfo, Scope, SpanInfo}; const LINT_MESSAGE: &str = "This `#[allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; @@ -34,6 +31,19 @@ dylint_linting::impl_late_lint!( } ); +#[derive(Eq, Hash, PartialEq, Debug, Clone)] +pub struct AllowInfo { + pub lint_name: String, + pub span: Span, + pub scope: Scope, +} + +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +pub enum Scope { + Crate, + Other, +} + #[derive(Default, Debug, Clone)] struct UnnecessaryLintAllow { findings: HashSet<AllowInfo>, @@ -47,21 +57,19 @@ impl UnnecessaryLintAllow { scope: Scope, span: Span, ) { + if span.from_expansion() { + return; + } + let attrs = cx.tcx.hir().attrs(hir_id); if !attrs.is_empty() { for attr in attrs.iter() { - self.collect_attribute(cx, attr, scope, span); + self.collect_attribute(attr, scope, span); } } } - fn collect_attribute( - &mut self, - cx: &LateContext, - attr: &Attribute, - scope: Scope, - item_span: Span, - ) { + fn collect_attribute(&mut self, attr: &Attribute, scope: Scope, span: Span) { if_chain! { if !attr.span.from_expansion(); if attr.has_name(sym::allow); @@ -72,7 +80,7 @@ impl UnnecessaryLintAllow { for lint_name in lint_names { self.findings.insert(AllowInfo { lint_name, - span: SpanInfo::from_span(cx, item_span), + span, scope, }); } @@ -113,12 +121,10 @@ impl UnnecessaryLintAllow { impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { fn check_crate_post(&mut self, _: &LateContext<'tcx>) { for finding in &self.findings { - println!( - "Found unnecessary `#[allow({})]` attribute at {}:{}-{}, type: {:?}", - finding.lint_name, - finding.span.file_name, - finding.span.from_line, - finding.span.to_line, + dbg!( + "Found unnecessary `#[allow({})]` attribute at {:?}, type: {:?}", + finding.lint_name.clone(), + finding.span, finding.scope ); } @@ -135,28 +141,16 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if item.span.from_expansion() { - return; - } - // Collect item-level attributes (struct, enum, impl) self.check_and_collect_attrs(cx, item.hir_id(), Scope::Other, item.span); } fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) { - if stmt.span.from_expansion() { - return; - } - // Collect statement-level attributes (let, return, etc.) self.check_and_collect_attrs(cx, stmt.hir_id, Scope::Other, stmt.span); } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { - if expr.span.from_expansion() { - return; - } - // Collect expression-level attributes (function call, etc.) self.check_and_collect_attrs(cx, expr.hir_id, Scope::Other, expr.span); } @@ -170,10 +164,6 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { span: Span, local_def_id: LocalDefId, ) { - if span.from_expansion() { - return; - } - // Collect function level attributes (function) let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); self.check_and_collect_attrs(cx, hir_id, Scope::Other, span); diff --git a/detectors/unnecessary-lint-allow/src/types.rs b/detectors/unnecessary-lint-allow/src/types.rs deleted file mode 100644 index e3838cf2..00000000 --- a/detectors/unnecessary-lint-allow/src/types.rs +++ /dev/null @@ -1,44 +0,0 @@ -use rustc_lint::{LateContext, LintContext}; -use rustc_span::{FileName, FileNameDisplayPreference, Span}; - -#[derive(Eq, Hash, PartialEq, Debug, Clone)] -pub struct AllowInfo { - pub lint_name: String, - pub span: SpanInfo, - pub scope: Scope, -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub enum Scope { - Crate, - Other, -} - -#[derive(Eq, PartialEq, Hash, Debug, Clone)] -pub struct SpanInfo { - pub file_name: String, - pub from_line: usize, - pub to_line: usize, -} - -impl SpanInfo { - pub fn from_span(cx: &LateContext, span: Span) -> Self { - let source_map = cx.sess().source_map(); - let file = source_map.lookup_source_file(span.lo()); - let file_name = match &file.name { - FileName::Real(name) => name - .to_string_lossy(FileNameDisplayPreference::Remapped) - .into_owned(), - _ => String::from("<unknown>"), - }; - - let lo_loc = source_map.lookup_char_pos(span.lo()); - let hi_loc = source_map.lookup_char_pos(span.hi()); - - SpanInfo { - file_name, - from_line: lo_loc.line, - to_line: hi_loc.line, - } - } -} From 2019ff3e842762d90524a4e817196c4b3b8057db Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Fri, 9 Aug 2024 16:20:21 -0300 Subject: [PATCH 07/18] Remove scope from detector, use clippy-wrappers --- detectors/unnecessary-lint-allow/Cargo.toml | 1 + detectors/unnecessary-lint-allow/src/lib.rs | 51 ++++++--------------- 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/detectors/unnecessary-lint-allow/Cargo.toml b/detectors/unnecessary-lint-allow/Cargo.toml index 925700a4..dd04a840 100644 --- a/detectors/unnecessary-lint-allow/Cargo.toml +++ b/detectors/unnecessary-lint-allow/Cargo.toml @@ -8,6 +8,7 @@ crate-type = ["cdylib"] [dependencies] clippy_utils = { workspace = true } +clippy_wrappers = { workspace = true } dylint_linting = { workspace = true } if_chain = { workspace = true } serde = { version = "1", features = ["derive"] } diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 56aa1cf5..9b19b17b 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -4,13 +4,14 @@ extern crate rustc_ast; extern crate rustc_hir; extern crate rustc_span; +use clippy_wrappers::span_lint; use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, tokenstream::{TokenStream, TokenTree}, AttrArgs, AttrKind, Attribute, }; -use rustc_hir::{intravisit::FnKind, Body, FnDecl, HirId, Item, CRATE_HIR_ID}; +use rustc_hir::{intravisit::FnKind, Body, Expr, FnDecl, HirId, Item, Stmt, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; use rustc_span::{def_id::LocalDefId, sym, Span}; use std::collections::{HashSet, VecDeque}; @@ -35,13 +36,6 @@ dylint_linting::impl_late_lint!( pub struct AllowInfo { pub lint_name: String, pub span: Span, - pub scope: Scope, -} - -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -pub enum Scope { - Crate, - Other, } #[derive(Default, Debug, Clone)] @@ -50,13 +44,7 @@ struct UnnecessaryLintAllow { } impl UnnecessaryLintAllow { - fn check_and_collect_attrs( - &mut self, - cx: &LateContext, - hir_id: HirId, - scope: Scope, - span: Span, - ) { + fn check_and_collect_attrs(&mut self, cx: &LateContext, hir_id: HirId, span: Span) { if span.from_expansion() { return; } @@ -64,12 +52,12 @@ impl UnnecessaryLintAllow { let attrs = cx.tcx.hir().attrs(hir_id); if !attrs.is_empty() { for attr in attrs.iter() { - self.collect_attribute(attr, scope, span); + self.collect_attribute(attr, span); } } } - fn collect_attribute(&mut self, attr: &Attribute, scope: Scope, span: Span) { + fn collect_attribute(&mut self, attr: &Attribute, span: Span) { if_chain! { if !attr.span.from_expansion(); if attr.has_name(sym::allow); @@ -81,7 +69,6 @@ impl UnnecessaryLintAllow { self.findings.insert(AllowInfo { lint_name, span, - scope, }); } } @@ -119,40 +106,30 @@ impl UnnecessaryLintAllow { } impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { - fn check_crate_post(&mut self, _: &LateContext<'tcx>) { + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { for finding in &self.findings { - dbg!( - "Found unnecessary `#[allow({})]` attribute at {:?}, type: {:?}", - finding.lint_name.clone(), - finding.span, - finding.scope - ); + span_lint(cx, UNNECESSARY_LINT_ALLOW, finding.span, LINT_MESSAGE); } } fn check_crate(&mut self, cx: &LateContext<'tcx>) { // Collect crate-level attributes - self.check_and_collect_attrs( - cx, - CRATE_HIR_ID, - Scope::Crate, - cx.tcx.hir().span(CRATE_HIR_ID), - ); + self.check_and_collect_attrs(cx, CRATE_HIR_ID, cx.tcx.hir().span(CRATE_HIR_ID)); } fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { // Collect item-level attributes (struct, enum, impl) - self.check_and_collect_attrs(cx, item.hir_id(), Scope::Other, item.span); + self.check_and_collect_attrs(cx, item.hir_id(), item.span); } - fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) { + fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { // Collect statement-level attributes (let, return, etc.) - self.check_and_collect_attrs(cx, stmt.hir_id, Scope::Other, stmt.span); + self.check_and_collect_attrs(cx, stmt.hir_id, stmt.span); } - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { // Collect expression-level attributes (function call, etc.) - self.check_and_collect_attrs(cx, expr.hir_id, Scope::Other, expr.span); + self.check_and_collect_attrs(cx, expr.hir_id, expr.span); } fn check_fn( @@ -166,6 +143,6 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { ) { // Collect function level attributes (function) let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); - self.check_and_collect_attrs(cx, hir_id, Scope::Other, span); + self.check_and_collect_attrs(cx, hir_id, span); } } From 336ee9e789c878c62b0b8bc82b13b1ba1b61dc74 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Mon, 12 Aug 2024 12:17:28 -0300 Subject: [PATCH 08/18] Edit detector --- detectors/unnecessary-lint-allow/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 9b19b17b..e2d42536 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -13,7 +13,7 @@ use rustc_ast::{ }; use rustc_hir::{intravisit::FnKind, Body, Expr, FnDecl, HirId, Item, Stmt, CRATE_HIR_ID}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_span::{def_id::LocalDefId, sym, Span}; +use rustc_span::{def_id::LocalDefId, Span, Symbol}; use std::collections::{HashSet, VecDeque}; const LINT_MESSAGE: &str = "This `#[allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; @@ -60,7 +60,7 @@ impl UnnecessaryLintAllow { fn collect_attribute(&mut self, attr: &Attribute, span: Span) { if_chain! { if !attr.span.from_expansion(); - if attr.has_name(sym::allow); + if attr.has_name(Symbol::intern("scout_allow")); if let AttrKind::Normal(item) = &attr.kind; if let AttrArgs::Delimited(delimited_args) = &item.item.args; then { From 4c2a46c52e947ed01925baea2e6160b8900b0640 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Mon, 12 Aug 2024 15:03:13 -0300 Subject: [PATCH 09/18] Update detector and test-case --- detectors/unnecessary-lint-allow/src/lib.rs | 106 +++--------------- .../vulnerable-example/Cargo.toml | 1 + .../vulnerable-example/src/lib.rs | 3 +- 3 files changed, 21 insertions(+), 89 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index e2d42536..4bb2bc73 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -1,7 +1,6 @@ #![feature(rustc_private)] extern crate rustc_ast; -extern crate rustc_hir; extern crate rustc_span; use clippy_wrappers::span_lint; @@ -9,20 +8,18 @@ use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, tokenstream::{TokenStream, TokenTree}, - AttrArgs, AttrKind, Attribute, + AttrArgs, AttrKind, }; -use rustc_hir::{intravisit::FnKind, Body, Expr, FnDecl, HirId, Item, Stmt, CRATE_HIR_ID}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_span::{def_id::LocalDefId, Span, Symbol}; -use std::collections::{HashSet, VecDeque}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_span::Symbol; +use std::collections::VecDeque; const LINT_MESSAGE: &str = "This `#[allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; -dylint_linting::impl_late_lint!( +dylint_linting::declare_pre_expansion_lint! { pub UNNECESSARY_LINT_ALLOW, Warn, LINT_MESSAGE, - UnnecessaryLintAllow::default(), { name: "Unnecessary Lint Allow", long_message: "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them.", @@ -30,51 +27,9 @@ dylint_linting::impl_late_lint!( help: "https://coinfabrik.github.io/scout-soroban/docs/detectors/unnecessary-lint-allow", vulnerability_class: "Code Quality", } -); - -#[derive(Eq, Hash, PartialEq, Debug, Clone)] -pub struct AllowInfo { - pub lint_name: String, - pub span: Span, -} - -#[derive(Default, Debug, Clone)] -struct UnnecessaryLintAllow { - findings: HashSet<AllowInfo>, } impl UnnecessaryLintAllow { - fn check_and_collect_attrs(&mut self, cx: &LateContext, hir_id: HirId, span: Span) { - if span.from_expansion() { - return; - } - - let attrs = cx.tcx.hir().attrs(hir_id); - if !attrs.is_empty() { - for attr in attrs.iter() { - self.collect_attribute(attr, span); - } - } - } - - fn collect_attribute(&mut self, attr: &Attribute, span: Span) { - if_chain! { - if !attr.span.from_expansion(); - if attr.has_name(Symbol::intern("scout_allow")); - if let AttrKind::Normal(item) = &attr.kind; - if let AttrArgs::Delimited(delimited_args) = &item.item.args; - then { - let lint_names = self.extract_lint_names(&delimited_args.tokens); - for lint_name in lint_names { - self.findings.insert(AllowInfo { - lint_name, - span, - }); - } - } - } - } - fn extract_lint_names(&self, tokens: &TokenStream) -> Vec<String> { let mut lint_names = Vec::new(); let mut stack = VecDeque::new(); @@ -105,44 +60,19 @@ impl UnnecessaryLintAllow { } } -impl<'tcx> LateLintPass<'tcx> for UnnecessaryLintAllow { - fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { - for finding in &self.findings { - span_lint(cx, UNNECESSARY_LINT_ALLOW, finding.span, LINT_MESSAGE); +impl EarlyLintPass for UnnecessaryLintAllow { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { + if_chain! { + if !attr.span.from_expansion(); + if attr.has_name(Symbol::intern("scout_allow")); + if let AttrKind::Normal(item) = &attr.kind; + if let AttrArgs::Delimited(delimited_args) = &item.item.args; + then { + let lint_names = self.extract_lint_names(&delimited_args.tokens); + for lint_name in lint_names { + span_lint(cx, UNNECESSARY_LINT_ALLOW, attr.span, lint_name); + } + } } } - - fn check_crate(&mut self, cx: &LateContext<'tcx>) { - // Collect crate-level attributes - self.check_and_collect_attrs(cx, CRATE_HIR_ID, cx.tcx.hir().span(CRATE_HIR_ID)); - } - - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - // Collect item-level attributes (struct, enum, impl) - self.check_and_collect_attrs(cx, item.hir_id(), item.span); - } - - fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { - // Collect statement-level attributes (let, return, etc.) - self.check_and_collect_attrs(cx, stmt.hir_id, stmt.span); - } - - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Collect expression-level attributes (function call, etc.) - self.check_and_collect_attrs(cx, expr.hir_id, expr.span); - } - - fn check_fn( - &mut self, - cx: &LateContext<'tcx>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, - _: &'tcx Body<'tcx>, - span: Span, - local_def_id: LocalDefId, - ) { - // Collect function level attributes (function) - let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); - self.check_and_collect_attrs(cx, hir_id, span); - } } diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml index d4da8d0a..35927951 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/Cargo.toml @@ -8,6 +8,7 @@ version = "0.1.0" crate-type = ["cdylib"] [dependencies] +scout-utils = { version = "0.1.0" } soroban-sdk = { workspace = true } [dev-dependencies] diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs index 89e06e08..56de7638 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/vulnerable-example/src/lib.rs @@ -1,4 +1,5 @@ #![no_std] +use scout_utils::scout_allow; use soroban_sdk::{contract, contracterror, contractimpl}; #[contract] @@ -11,7 +12,7 @@ pub enum AssertError { } #[contractimpl] -#[allow(assert_violation)] +#[scout_allow(assert_violation)] impl UnnecessaryLintAllow { pub fn assert_if_greater_than_10(value: u128) -> Result<bool, AssertError> { if value <= 10 { From 6238cbc9aaf1b999c136446db4f0ba809acfe511 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Mon, 12 Aug 2024 15:21:38 -0300 Subject: [PATCH 10/18] Update detector --- detectors/unnecessary-lint-allow/src/lib.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 4bb2bc73..97e7ac98 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -3,7 +3,7 @@ extern crate rustc_ast; extern crate rustc_span; -use clippy_wrappers::span_lint; +use clippy_wrappers::span_lint_and_help; use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, @@ -14,7 +14,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_span::Symbol; use std::collections::VecDeque; -const LINT_MESSAGE: &str = "This `#[allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; +const LINT_MESSAGE: &str = "This `#[scout_allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; dylint_linting::declare_pre_expansion_lint! { pub UNNECESSARY_LINT_ALLOW, @@ -22,7 +22,7 @@ dylint_linting::declare_pre_expansion_lint! { LINT_MESSAGE, { name: "Unnecessary Lint Allow", - long_message: "The `#[allow]` attribute is used to disable lints. It is recommended to fix the issues instead of disabling them.", + long_message: "The `#[scout_allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered.", severity: "Enhancement", help: "https://coinfabrik.github.io/scout-soroban/docs/detectors/unnecessary-lint-allow", vulnerability_class: "Code Quality", @@ -70,7 +70,14 @@ impl EarlyLintPass for UnnecessaryLintAllow { then { let lint_names = self.extract_lint_names(&delimited_args.tokens); for lint_name in lint_names { - span_lint(cx, UNNECESSARY_LINT_ALLOW, attr.span, lint_name); + span_lint_and_help( + cx, + UNNECESSARY_LINT_ALLOW, + attr.span, + LINT_MESSAGE, + None, + format!("The detector `{}` is no longer triggered. Consider removing the `#[scout_allow({lint_name})]` attribute if the lint is no longer triggered.", lint_name) + ); } } } From 916afcb62cd0cdcb3234b4056aef734ad57ac1cb Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Tue, 13 Aug 2024 15:03:22 -0300 Subject: [PATCH 11/18] Edit detector --- detectors/unnecessary-lint-allow/src/lib.rs | 55 ++++++++++++--------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 97e7ac98..e1b45b0b 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] extern crate rustc_ast; +extern crate rustc_hir; extern crate rustc_span; use clippy_wrappers::span_lint_and_help; @@ -8,11 +9,12 @@ use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, tokenstream::{TokenStream, TokenTree}, - AttrArgs, AttrKind, + visit::FnKind, + AttrArgs, AttrKind, Attribute, Expr, HasAttrs, Item, NodeId, }; -use rustc_lint::{EarlyContext, EarlyLintPass}; -use rustc_span::Symbol; -use std::collections::VecDeque; +use rustc_lint::{EarlyContext, EarlyLintPass, LateLintPass, LintContext}; +use rustc_span::{Span, Symbol}; +use std::collections::{HashMap, VecDeque}; const LINT_MESSAGE: &str = "This `#[scout_allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; @@ -48,7 +50,6 @@ impl UnnecessaryLintAllow { lint_names.push(ident.to_string()); } TokenTree::Delimited(_, _, Delimiter::Parenthesis, inner_stream) => { - // Push the inner stream onto the stack for later processing stack.push_back(inner_stream); } _ => {} @@ -58,28 +59,34 @@ impl UnnecessaryLintAllow { lint_names } -} -impl EarlyLintPass for UnnecessaryLintAllow { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) { - if_chain! { - if !attr.span.from_expansion(); - if attr.has_name(Symbol::intern("scout_allow")); - if let AttrKind::Normal(item) = &attr.kind; - if let AttrArgs::Delimited(delimited_args) = &item.item.args; - then { - let lint_names = self.extract_lint_names(&delimited_args.tokens); - for lint_name in lint_names { - span_lint_and_help( - cx, - UNNECESSARY_LINT_ALLOW, - attr.span, - LINT_MESSAGE, - None, - format!("The detector `{}` is no longer triggered. Consider removing the `#[scout_allow({lint_name})]` attribute if the lint is no longer triggered.", lint_name) - ); + fn check_scout_allow_attrs(&self, cx: &EarlyContext<'_>, attrs: &[Attribute], span: Span) { + for attr in attrs { + if_chain! { + if !attr.span.from_expansion(); + if attr.has_name(Symbol::intern("scout_allow")); + if let AttrKind::Normal(item) = &attr.kind; + if let AttrArgs::Delimited(delimited_args) = &item.item.args; + then { + let lint_names = self.extract_lint_names(&delimited_args.tokens); + for lint_name in lint_names { + span_lint_and_help( + cx, + UNNECESSARY_LINT_ALLOW, + span, + LINT_MESSAGE, + None, + format!("The detector `{}` is no longer triggered. Consider removing the `#[scout_allow({})]` attribute if the lint is no longer triggered.", lint_name, lint_name) + ); + } } } } } } + +impl EarlyLintPass for UnnecessaryLintAllow { + fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + self.check_scout_allow_attrs(cx, &item.attrs, item.span); + } +} From a7be1a9f00580ce7f8e570c9efc4b6af7ae8a146 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Thu, 15 Aug 2024 16:18:57 -0300 Subject: [PATCH 12/18] Update detector --- detectors/unnecessary-lint-allow/Cargo.toml | 1 + detectors/unnecessary-lint-allow/src/lib.rs | 21 ++- .../unnecessary-lint-allow/src/processor.rs | 131 ++++++++++++++++++ 3 files changed, 146 insertions(+), 7 deletions(-) create mode 100644 detectors/unnecessary-lint-allow/src/processor.rs diff --git a/detectors/unnecessary-lint-allow/Cargo.toml b/detectors/unnecessary-lint-allow/Cargo.toml index dd04a840..cd203eeb 100644 --- a/detectors/unnecessary-lint-allow/Cargo.toml +++ b/detectors/unnecessary-lint-allow/Cargo.toml @@ -12,6 +12,7 @@ clippy_wrappers = { workspace = true } dylint_linting = { workspace = true } if_chain = { workspace = true } serde = { version = "1", features = ["derive"] } +serde_json = "=1.0.120" [package.metadata.rust-analyzer] rustc_private = true diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index e1b45b0b..41f3a82f 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -4,17 +4,19 @@ extern crate rustc_ast; extern crate rustc_hir; extern crate rustc_span; +mod processor; +pub use processor::should_include_finding; + use clippy_wrappers::span_lint_and_help; use if_chain::if_chain; use rustc_ast::{ token::{Delimiter, Token, TokenKind}, tokenstream::{TokenStream, TokenTree}, - visit::FnKind, - AttrArgs, AttrKind, Attribute, Expr, HasAttrs, Item, NodeId, + AttrArgs, AttrKind, Attribute, Item, ItemKind, }; -use rustc_lint::{EarlyContext, EarlyLintPass, LateLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_span::{Span, Symbol}; -use std::collections::{HashMap, VecDeque}; +use std::collections::VecDeque; const LINT_MESSAGE: &str = "This `#[scout_allow]` attribute may be unnecessary. Consider removing it if the lint is no longer triggered."; @@ -34,10 +36,9 @@ dylint_linting::declare_pre_expansion_lint! { impl UnnecessaryLintAllow { fn extract_lint_names(&self, tokens: &TokenStream) -> Vec<String> { let mut lint_names = Vec::new(); - let mut stack = VecDeque::new(); - stack.push_back(tokens); + let mut stack = VecDeque::from([tokens]); - while let Some(current_stream) = stack.pop_back() { + while let Some(current_stream) = stack.pop_front() { for tree in current_stream.trees() { match tree { TokenTree::Token( @@ -88,5 +89,11 @@ impl UnnecessaryLintAllow { impl EarlyLintPass for UnnecessaryLintAllow { fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { self.check_scout_allow_attrs(cx, &item.attrs, item.span); + + if let ItemKind::Impl(impl_) = &item.kind { + for impl_item in &impl_.items { + self.check_scout_allow_attrs(cx, &impl_item.attrs, impl_item.span); + } + } } } diff --git a/detectors/unnecessary-lint-allow/src/processor.rs b/detectors/unnecessary-lint-allow/src/processor.rs new file mode 100644 index 00000000..7a4d4d6b --- /dev/null +++ b/detectors/unnecessary-lint-allow/src/processor.rs @@ -0,0 +1,131 @@ + use serde::de::Error; + use serde_json::Value; + use std::{collections::HashMap, ffi::CStr, os::raw::c_char}; + + /// Determines whether a finding should be included. + /// + /// # Safety + /// + /// This function is marked as unsafe because it deals with raw pointers. + /// The caller is responsible for ensuring the safety of the pointers passed as arguments. + #[no_mangle] + pub unsafe extern "C" fn should_include_finding( + finding_json: *const c_char, + all_findings_json: *const c_char, + ) -> bool { + // Check for null pointers + if finding_json.is_null() || all_findings_json.is_null() { + return false; + } + + let finding = match parse_json_value(finding_json) { + Ok(v) => v, + Err(_) => return false, + }; + + let all_findings: Vec<Value> = match parse_json_array(all_findings_json) { + Ok(v) => v, + Err(_) => return false, + }; + + should_include_finding_impl(&finding, &all_findings) + } + + // Helper function to safely parse a single JSON value + unsafe fn parse_json_value(input: *const c_char) -> Result<Value, serde_json::Error> { + let c_str = CStr::from_ptr(input); + let input_str = c_str + .to_str() + .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; + serde_json::from_str(input_str) + } + + // Helper function to safely parse a JSON array + unsafe fn parse_json_array(input: *const c_char) -> Result<Vec<Value>, serde_json::Error> { + let c_str = CStr::from_ptr(input); + let input_str = c_str + .to_str() + .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; + serde_json::from_str(input_str) + } + + #[derive(Debug, Clone)] + struct Finding { + detector: String, + file_name: String, + span: (usize, usize), + allowed_lint: Option<String>, + } + + fn spans_overlap(span1: (usize, usize), span2: (usize, usize)) -> bool { + span1.0 <= span2.1 && span2.0 <= span1.1 + } + + fn parse_finding(finding: &Value) -> Option<Finding> { + let code = finding.get("code")?.get("code")?.as_str()?; + let span = finding.get("spans")?.as_array()?.first()?; + let file_name = span.get("file_name")?.as_str()?; + let line_start = span.get("line_start")?.as_u64()?; + let line_end = span.get("line_end")?.as_u64()?; + + let allowed_lint = if code == "unnecessary_lint_allow" { + finding + .get("children")? + .get(0)? + .get("message")? + .as_str() + .and_then(|msg| msg.split('`').nth(1).map(String::from)) + } else { + None + }; + + Some(Finding { + detector: code.to_string(), + file_name: file_name.to_string(), + span: (line_start as usize, line_end as usize), + allowed_lint, + }) + } + + pub fn should_include_finding_impl(finding: &Value, all_findings: &[Value]) -> bool { + let current_finding = match parse_finding(finding) { + Some(f) => f, + None => return false, // If we can't parse the finding, we don't include it + }; + + let mut findings_by_file: HashMap<String, Vec<Finding>> = HashMap::new(); + for f in all_findings { + if let Some(parsed) = parse_finding(f) { + findings_by_file + .entry(parsed.file_name.clone()) + .or_default() + .push(parsed); + } + } + + if let Some(file_findings) = findings_by_file.get(¤t_finding.file_name) { + let (unnecessary_allows, other_findings): (Vec<_>, Vec<_>) = file_findings + .iter() + .partition(|f| f.detector == "unnecessary_lint_allow"); + + if current_finding.detector == "unnecessary_lint_allow" { + if let Some(allowed_lint) = ¤t_finding.allowed_lint { + let lint_present = other_findings.iter().any(|f| { + &f.detector == allowed_lint && spans_overlap(f.span, current_finding.span) + }); + return !lint_present; // Include if the lint is not present (unnecessary allow) + } + } else { + let is_allowed = unnecessary_allows.iter().any(|allow| { + allow + .allowed_lint + .as_ref() + .map_or(false, |lint| lint == ¤t_finding.detector) + && spans_overlap(allow.span, current_finding.span) + }); + return !is_allowed; // Include if the finding is not allowed + } + } + + true // If we can't find the file or process the finding, we include it by default + } From 166b2b2d43ed0abd9b88d4b98b39bc5bded088d6 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Fri, 16 Aug 2024 13:17:34 -0300 Subject: [PATCH 13/18] Improve some preprocessing stuff --- .../unnecessary-lint-allow/src/processor.rs | 239 +++++++++--------- 1 file changed, 117 insertions(+), 122 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/processor.rs b/detectors/unnecessary-lint-allow/src/processor.rs index 7a4d4d6b..e1f04bf6 100644 --- a/detectors/unnecessary-lint-allow/src/processor.rs +++ b/detectors/unnecessary-lint-allow/src/processor.rs @@ -1,131 +1,126 @@ - use serde::de::Error; - use serde_json::Value; - use std::{collections::HashMap, ffi::CStr, os::raw::c_char}; - - /// Determines whether a finding should be included. - /// - /// # Safety - /// - /// This function is marked as unsafe because it deals with raw pointers. - /// The caller is responsible for ensuring the safety of the pointers passed as arguments. - #[no_mangle] - pub unsafe extern "C" fn should_include_finding( - finding_json: *const c_char, - all_findings_json: *const c_char, - ) -> bool { - // Check for null pointers - if finding_json.is_null() || all_findings_json.is_null() { - return false; - } - - let finding = match parse_json_value(finding_json) { - Ok(v) => v, - Err(_) => return false, - }; - - let all_findings: Vec<Value> = match parse_json_array(all_findings_json) { - Ok(v) => v, - Err(_) => return false, - }; - - should_include_finding_impl(&finding, &all_findings) - } - - // Helper function to safely parse a single JSON value - unsafe fn parse_json_value(input: *const c_char) -> Result<Value, serde_json::Error> { - let c_str = CStr::from_ptr(input); - let input_str = c_str - .to_str() - .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; - serde_json::from_str(input_str) - } - - // Helper function to safely parse a JSON array - unsafe fn parse_json_array(input: *const c_char) -> Result<Vec<Value>, serde_json::Error> { - let c_str = CStr::from_ptr(input); - let input_str = c_str - .to_str() - .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; - serde_json::from_str(input_str) - } - - #[derive(Debug, Clone)] - struct Finding { - detector: String, - file_name: String, - span: (usize, usize), - allowed_lint: Option<String>, - } - - fn spans_overlap(span1: (usize, usize), span2: (usize, usize)) -> bool { - span1.0 <= span2.1 && span2.0 <= span1.1 +use serde::de::Error; +use serde_json::Value; +use std::{collections::HashMap, ffi::CStr, os::raw::c_char}; + +/// Determines whether a finding should be included. +/// +/// # Safety +/// +/// This function is marked as unsafe because it deals with raw pointers. +/// The caller is responsible for ensuring the safety of the pointers passed as arguments. +#[no_mangle] +pub unsafe extern "C" fn should_include_finding( + finding_json: *const c_char, + all_findings_json: *const c_char, +) -> bool { + // Check for null pointers + if finding_json.is_null() || all_findings_json.is_null() { + return false; } - fn parse_finding(finding: &Value) -> Option<Finding> { - let code = finding.get("code")?.get("code")?.as_str()?; - let span = finding.get("spans")?.as_array()?.first()?; - let file_name = span.get("file_name")?.as_str()?; - let line_start = span.get("line_start")?.as_u64()?; - let line_end = span.get("line_end")?.as_u64()?; - - let allowed_lint = if code == "unnecessary_lint_allow" { - finding - .get("children")? - .get(0)? - .get("message")? - .as_str() - .and_then(|msg| msg.split('`').nth(1).map(String::from)) - } else { - None - }; - - Some(Finding { - detector: code.to_string(), - file_name: file_name.to_string(), - span: (line_start as usize, line_end as usize), - allowed_lint, - }) - } - - pub fn should_include_finding_impl(finding: &Value, all_findings: &[Value]) -> bool { - let current_finding = match parse_finding(finding) { - Some(f) => f, - None => return false, // If we can't parse the finding, we don't include it - }; - - let mut findings_by_file: HashMap<String, Vec<Finding>> = HashMap::new(); - for f in all_findings { - if let Some(parsed) = parse_finding(f) { - findings_by_file - .entry(parsed.file_name.clone()) - .or_default() - .push(parsed); - } + let finding = match parse_json(finding_json) { + Ok(v) => v, + Err(_) => return false, + }; + + let all_findings = match parse_json(all_findings_json) { + Ok(Value::Array(v)) => v, + _ => return false, + }; + + should_include_finding_impl(&finding, &all_findings) +} + +unsafe fn parse_json(input: *const c_char) -> Result<Value, serde_json::Error> { + let c_str = CStr::from_ptr(input); + let input_str = c_str + .to_str() + .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; + serde_json::from_str(input_str) +} + +#[derive(Debug, Clone)] +struct Finding { + detector: String, + file_name: String, + span: (usize, usize), + allowed_lint: Option<String>, +} + +fn spans_overlap(span1: (usize, usize), span2: (usize, usize)) -> bool { + span1.0 <= span2.1 && span2.0 <= span1.1 +} + +fn parse_finding(finding: &Value) -> Option<Finding> { + let detector = finding.get("code")?.get("code")?.as_str()?; + let span = finding.get("spans")?.as_array()?.first()?; + let file_name = span.get("file_name")?.as_str()?; + let line_start = span.get("line_start")?.as_u64()?; + let line_end = span.get("line_end")?.as_u64()?; + + let allowed_lint = if detector == "unnecessary_lint_allow" { + finding + .get("children")? + .get(0)? + .get("message")? + .as_str() + .and_then(|msg| msg.split('`').nth(1).map(String::from)) + } else { + None + }; + + // Check for potential integer overflow when converting from u64 to usize + let start = usize::try_from(line_start).ok()?; + let end = usize::try_from(line_end).ok()?; + + Some(Finding { + detector: detector.to_owned(), + file_name: file_name.to_owned(), + span: (start, end), + allowed_lint, + }) +} + +pub fn should_include_finding_impl(finding: &Value, all_findings: &[Value]) -> bool { + let current_finding = match parse_finding(finding) { + Some(f) => f, + None => return false, // If we can't parse the finding, we don't include it + }; + + let mut findings_by_file: HashMap<String, Vec<Finding>> = HashMap::new(); + for f in all_findings { + if let Some(parsed) = parse_finding(f) { + findings_by_file + .entry(parsed.file_name.clone()) + .or_default() + .push(parsed); } + } - if let Some(file_findings) = findings_by_file.get(¤t_finding.file_name) { - let (unnecessary_allows, other_findings): (Vec<_>, Vec<_>) = file_findings - .iter() - .partition(|f| f.detector == "unnecessary_lint_allow"); + if let Some(file_findings) = findings_by_file.get(¤t_finding.file_name) { + let (unnecessary_allows, other_findings): (Vec<_>, Vec<_>) = file_findings + .iter() + .partition(|f| f.detector == "unnecessary_lint_allow"); - if current_finding.detector == "unnecessary_lint_allow" { - if let Some(allowed_lint) = ¤t_finding.allowed_lint { - let lint_present = other_findings.iter().any(|f| { - &f.detector == allowed_lint && spans_overlap(f.span, current_finding.span) - }); - return !lint_present; // Include if the lint is not present (unnecessary allow) - } - } else { - let is_allowed = unnecessary_allows.iter().any(|allow| { - allow - .allowed_lint - .as_ref() - .map_or(false, |lint| lint == ¤t_finding.detector) - && spans_overlap(allow.span, current_finding.span) + if current_finding.detector == "unnecessary_lint_allow" { + if let Some(allowed_lint) = ¤t_finding.allowed_lint { + let lint_present = other_findings.iter().any(|f| { + &f.detector == allowed_lint && spans_overlap(f.span, current_finding.span) }); - return !is_allowed; // Include if the finding is not allowed + !lint_present // Include if the lint is not present (unnecessary allow) + } else { + true // Include if we can't determine the allowed lint } + } else { + !unnecessary_allows.iter().any(|allow| { + allow + .allowed_lint + .as_ref() + .map_or(false, |lint| lint == ¤t_finding.detector) + && spans_overlap(allow.span, current_finding.span) + }) // Include if the finding is not allowed } - - true // If we can't find the file or process the finding, we include it by default + } else { + true // If we can't find the file, we include it by default } +} From 8bf4ef51517c065b4254132ec36714879055cfe1 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Mon, 26 Aug 2024 16:03:20 -0300 Subject: [PATCH 14/18] Add suppressing message on remediated to test it works --- .../remediated-example/Cargo.toml | 1 + .../remediated-example/src/lib.rs | 20 ++++++------------- 2 files changed, 7 insertions(+), 14 deletions(-) diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml index cb27925d..42527218 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/Cargo.toml @@ -8,6 +8,7 @@ version = "0.1.0" crate-type = ["cdylib"] [dependencies] +scout-utils = { version = "0.1.0" } soroban-sdk = { workspace = true } [dev-dependencies] diff --git a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs index 73fba1db..0e218e20 100644 --- a/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs +++ b/test-cases/unnecessary-lint-allow/unnecessary-lint-allow-1/remediated-example/src/lib.rs @@ -1,23 +1,15 @@ #![no_std] - -use soroban_sdk::{contract, contracterror, contractimpl}; +use scout_utils::scout_allow; +use soroban_sdk::{contract, contractimpl}; #[contract] pub struct UnnecessaryLintAllow; -#[contracterror] -#[derive(Copy, Clone)] -pub enum AssertError { - GreaterThan10 = 1, -} - #[contractimpl] +#[scout_allow(assert_violation)] impl UnnecessaryLintAllow { - pub fn assert_if_greater_than_10(value: u128) -> Result<bool, AssertError> { - if value <= 10 { - Ok(true) - } else { - Err(AssertError::GreaterThan10) - } + pub fn assert_if_greater_than_10(value: u128) -> bool { + assert!(value <= 10); + true } } From 45bb204075417c7dfa1e4ad6261cbd35d390c4a7 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Tue, 27 Aug 2024 11:24:50 -0300 Subject: [PATCH 15/18] Add loop into detector --- detectors/unnecessary-lint-allow/src/lib.rs | 2 +- .../unnecessary-lint-allow/src/processor.rs | 86 +++++++++++++++---- 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/lib.rs b/detectors/unnecessary-lint-allow/src/lib.rs index 41f3a82f..bbeb5952 100644 --- a/detectors/unnecessary-lint-allow/src/lib.rs +++ b/detectors/unnecessary-lint-allow/src/lib.rs @@ -5,7 +5,7 @@ extern crate rustc_hir; extern crate rustc_span; mod processor; -pub use processor::should_include_finding; +pub use processor::process_findings; use clippy_wrappers::span_lint_and_help; use if_chain::if_chain; diff --git a/detectors/unnecessary-lint-allow/src/processor.rs b/detectors/unnecessary-lint-allow/src/processor.rs index e1f04bf6..9da0ffc9 100644 --- a/detectors/unnecessary-lint-allow/src/processor.rs +++ b/detectors/unnecessary-lint-allow/src/processor.rs @@ -1,34 +1,40 @@ use serde::de::Error; use serde_json::Value; -use std::{collections::HashMap, ffi::CStr, os::raw::c_char}; +use std::{collections::HashMap, ffi::CStr, ffi::CString, os::raw::c_char}; -/// Determines whether a finding should be included. +/// Process the findings to filter out unnecessary findings. /// /// # Safety /// /// This function is marked as unsafe because it deals with raw pointers. /// The caller is responsible for ensuring the safety of the pointers passed as arguments. #[no_mangle] -pub unsafe extern "C" fn should_include_finding( - finding_json: *const c_char, - all_findings_json: *const c_char, -) -> bool { - // Check for null pointers - if finding_json.is_null() || all_findings_json.is_null() { - return false; - } - - let finding = match parse_json(finding_json) { - Ok(v) => v, - Err(_) => return false, +pub unsafe extern "C" fn process_findings( + successful_findings_json: *const c_char, + output_json: *const c_char, + inside_vscode: bool, +) -> *mut c_char { + let successful_findings = match parse_json(successful_findings_json) { + Ok(Value::Array(v)) => v, + _ => return std::ptr::null_mut(), }; - let all_findings = match parse_json(all_findings_json) { + let output = match parse_json(output_json) { Ok(Value::Array(v)) => v, - _ => return false, + _ => return std::ptr::null_mut(), }; - should_include_finding_impl(&finding, &all_findings) + let (console_findings, output_string_vscode) = + process_findings_impl(successful_findings, output, inside_vscode); + + let result = serde_json::json!({ + "console_findings": console_findings, + "output_string_vscode": output_string_vscode + }); + + let result_string = serde_json::to_string(&result).unwrap_or_default(); + let c_str = CString::new(result_string).unwrap_or_default(); + c_str.into_raw() } unsafe fn parse_json(input: *const c_char) -> Result<Value, serde_json::Error> { @@ -81,6 +87,52 @@ fn parse_finding(finding: &Value) -> Option<Finding> { }) } +fn process_findings_impl( + successful_findings: Vec<Value>, + output: Vec<Value>, + inside_vscode: bool, +) -> (Vec<Value>, String) { + let console_findings: Vec<_> = successful_findings + .iter() + .filter(|&finding| should_include_finding_impl(finding, &successful_findings)) + .cloned() + .collect(); + + let output_vscode: Vec<_> = if inside_vscode { + let all_findings: Vec<_> = output + .iter() + .filter_map(|val| val.get("message").cloned()) + .collect(); + + output + .into_iter() + .filter(|val| { + val.get("message") + .map(|message| should_include_finding_impl(message, &all_findings)) + .unwrap_or(true) + }) + .collect() + } else { + Vec::new() + }; + + let output_string_vscode = output_vscode + .into_iter() + .filter_map(|finding| serde_json::to_string(&finding).ok()) + .collect::<Vec<_>>() + .join("\n"); + + (console_findings, output_string_vscode) +} + +// Add this function to free the memory allocated by process_findings +#[no_mangle] +pub unsafe extern "C" fn free_string(ptr: *mut c_char) { + if !ptr.is_null() { + let _ = CString::from_raw(ptr); + } +} + pub fn should_include_finding_impl(finding: &Value, all_findings: &[Value]) -> bool { let current_finding = match parse_finding(finding) { Some(f) => f, From 6b25c711a7408fc8fca973bc80ba8fb68b7e5fe9 Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Tue, 27 Aug 2024 11:30:53 -0300 Subject: [PATCH 16/18] Organize code and cache some stuff --- .../unnecessary-lint-allow/src/processor.rs | 190 ++++++++++-------- 1 file changed, 107 insertions(+), 83 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/processor.rs b/detectors/unnecessary-lint-allow/src/processor.rs index 9da0ffc9..c1a3e714 100644 --- a/detectors/unnecessary-lint-allow/src/processor.rs +++ b/detectors/unnecessary-lint-allow/src/processor.rs @@ -2,49 +2,6 @@ use serde::de::Error; use serde_json::Value; use std::{collections::HashMap, ffi::CStr, ffi::CString, os::raw::c_char}; -/// Process the findings to filter out unnecessary findings. -/// -/// # Safety -/// -/// This function is marked as unsafe because it deals with raw pointers. -/// The caller is responsible for ensuring the safety of the pointers passed as arguments. -#[no_mangle] -pub unsafe extern "C" fn process_findings( - successful_findings_json: *const c_char, - output_json: *const c_char, - inside_vscode: bool, -) -> *mut c_char { - let successful_findings = match parse_json(successful_findings_json) { - Ok(Value::Array(v)) => v, - _ => return std::ptr::null_mut(), - }; - - let output = match parse_json(output_json) { - Ok(Value::Array(v)) => v, - _ => return std::ptr::null_mut(), - }; - - let (console_findings, output_string_vscode) = - process_findings_impl(successful_findings, output, inside_vscode); - - let result = serde_json::json!({ - "console_findings": console_findings, - "output_string_vscode": output_string_vscode - }); - - let result_string = serde_json::to_string(&result).unwrap_or_default(); - let c_str = CString::new(result_string).unwrap_or_default(); - c_str.into_raw() -} - -unsafe fn parse_json(input: *const c_char) -> Result<Value, serde_json::Error> { - let c_str = CStr::from_ptr(input); - let input_str = c_str - .to_str() - .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; - serde_json::from_str(input_str) -} - #[derive(Debug, Clone)] struct Finding { detector: String, @@ -53,8 +10,43 @@ struct Finding { allowed_lint: Option<String>, } -fn spans_overlap(span1: (usize, usize), span2: (usize, usize)) -> bool { - span1.0 <= span2.1 && span2.0 <= span1.1 +struct FileFindings { + unnecessary_allows: Vec<Finding>, + other_findings: Vec<Finding>, +} + +struct FindingsCache { + by_file: HashMap<String, FileFindings>, +} + +impl FindingsCache { + fn new(all_findings: &[Value]) -> Self { + let mut by_file: HashMap<String, FileFindings> = HashMap::new(); + + for finding in all_findings { + if let Some(parsed) = parse_finding(finding) { + by_file + .entry(parsed.file_name.clone()) + .or_insert_with(|| FileFindings { + unnecessary_allows: Vec::new(), + other_findings: Vec::new(), + }) + .add_finding(parsed); + } + } + + FindingsCache { by_file } + } +} + +impl FileFindings { + fn add_finding(&mut self, finding: Finding) { + if finding.detector == "unnecessary_lint_allow" { + self.unnecessary_allows.push(finding); + } else { + self.other_findings.push(finding); + } + } } fn parse_finding(finding: &Value) -> Option<Finding> { @@ -87,28 +79,28 @@ fn parse_finding(finding: &Value) -> Option<Finding> { }) } +fn spans_overlap(span1: (usize, usize), span2: (usize, usize)) -> bool { + span1.0 <= span2.1 && span2.0 <= span1.1 +} + fn process_findings_impl( successful_findings: Vec<Value>, output: Vec<Value>, inside_vscode: bool, ) -> (Vec<Value>, String) { + let findings_cache = FindingsCache::new(&successful_findings); + let console_findings: Vec<_> = successful_findings - .iter() - .filter(|&finding| should_include_finding_impl(finding, &successful_findings)) - .cloned() + .into_iter() + .filter(|finding| should_include_finding_impl(finding, &findings_cache)) .collect(); let output_vscode: Vec<_> = if inside_vscode { - let all_findings: Vec<_> = output - .iter() - .filter_map(|val| val.get("message").cloned()) - .collect(); - output .into_iter() .filter(|val| { val.get("message") - .map(|message| should_include_finding_impl(message, &all_findings)) + .map(|message| should_include_finding_impl(message, &findings_cache)) .unwrap_or(true) }) .collect() @@ -125,54 +117,86 @@ fn process_findings_impl( (console_findings, output_string_vscode) } -// Add this function to free the memory allocated by process_findings -#[no_mangle] -pub unsafe extern "C" fn free_string(ptr: *mut c_char) { - if !ptr.is_null() { - let _ = CString::from_raw(ptr); - } -} - -pub fn should_include_finding_impl(finding: &Value, all_findings: &[Value]) -> bool { +fn should_include_finding_impl(finding: &Value, cache: &FindingsCache) -> bool { let current_finding = match parse_finding(finding) { Some(f) => f, None => return false, // If we can't parse the finding, we don't include it }; - let mut findings_by_file: HashMap<String, Vec<Finding>> = HashMap::new(); - for f in all_findings { - if let Some(parsed) = parse_finding(f) { - findings_by_file - .entry(parsed.file_name.clone()) - .or_default() - .push(parsed); - } - } - - if let Some(file_findings) = findings_by_file.get(¤t_finding.file_name) { - let (unnecessary_allows, other_findings): (Vec<_>, Vec<_>) = file_findings - .iter() - .partition(|f| f.detector == "unnecessary_lint_allow"); - + if let Some(file_findings) = cache.by_file.get(¤t_finding.file_name) { if current_finding.detector == "unnecessary_lint_allow" { if let Some(allowed_lint) = ¤t_finding.allowed_lint { - let lint_present = other_findings.iter().any(|f| { + !file_findings.other_findings.iter().any(|f| { &f.detector == allowed_lint && spans_overlap(f.span, current_finding.span) - }); - !lint_present // Include if the lint is not present (unnecessary allow) + }) } else { true // Include if we can't determine the allowed lint } } else { - !unnecessary_allows.iter().any(|allow| { + !file_findings.unnecessary_allows.iter().any(|allow| { allow .allowed_lint .as_ref() .map_or(false, |lint| lint == ¤t_finding.detector) && spans_overlap(allow.span, current_finding.span) - }) // Include if the finding is not allowed + }) } } else { true // If we can't find the file, we include it by default } } + +/// Process the findings to filter out unnecessary findings. +/// +/// # Safety +/// +/// This function is marked as unsafe because it deals with raw pointers. +/// The caller is responsible for ensuring the safety of the pointers passed as arguments. +#[no_mangle] +pub unsafe extern "C" fn process_findings( + successful_findings_json: *const c_char, + output_json: *const c_char, + inside_vscode: bool, +) -> *mut c_char { + let successful_findings = match parse_json(successful_findings_json) { + Ok(Value::Array(v)) => v, + _ => return std::ptr::null_mut(), + }; + + let output = match parse_json(output_json) { + Ok(Value::Array(v)) => v, + _ => return std::ptr::null_mut(), + }; + + let (console_findings, output_string_vscode) = + process_findings_impl(successful_findings, output, inside_vscode); + + let result = serde_json::json!({ + "console_findings": console_findings, + "output_string_vscode": output_string_vscode + }); + + match serde_json::to_string(&result) { + Ok(result_string) => match CString::new(result_string) { + Ok(c_str) => c_str.into_raw(), + Err(_) => std::ptr::null_mut(), + }, + Err(_) => std::ptr::null_mut(), + } +} + +unsafe fn parse_json(input: *const c_char) -> Result<Value, serde_json::Error> { + let c_str = CStr::from_ptr(input); + let input_str = c_str + .to_str() + .map_err(|_| serde_json::Error::custom("Invalid UTF-8"))?; + serde_json::from_str(input_str) +} + +// Add this function to free the memory allocated by process_findings +#[no_mangle] +pub unsafe extern "C" fn free_string(ptr: *mut c_char) { + if !ptr.is_null() { + let _ = CString::from_raw(ptr); + } +} From 0d06d3ec06dbf9fff7aaa58fb6e523abb6b27ea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Garc=C3=ADa=20Crosta?= <jgcrosta@gmail.com> Date: Tue, 27 Aug 2024 11:35:40 -0300 Subject: [PATCH 17/18] Update template Cargo.toml --- templates/test-case/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/templates/test-case/Cargo.toml b/templates/test-case/Cargo.toml index 9a687e66..5f4afc5d 100644 --- a/templates/test-case/Cargo.toml +++ b/templates/test-case/Cargo.toml @@ -27,5 +27,4 @@ strip = "symbols" [profile.release-with-logs] debug-assertions = true - inherits = "release" From 778806c6dcc6a84dc85db25011b68eb5eafae56a Mon Sep 17 00:00:00 2001 From: Jose Garcia Crosta <jgcrosta@gmail.com> Date: Tue, 27 Aug 2024 11:54:49 -0300 Subject: [PATCH 18/18] Update comments --- detectors/unnecessary-lint-allow/src/processor.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/detectors/unnecessary-lint-allow/src/processor.rs b/detectors/unnecessary-lint-allow/src/processor.rs index c1a3e714..dfc1b3af 100644 --- a/detectors/unnecessary-lint-allow/src/processor.rs +++ b/detectors/unnecessary-lint-allow/src/processor.rs @@ -67,7 +67,6 @@ fn parse_finding(finding: &Value) -> Option<Finding> { None }; - // Check for potential integer overflow when converting from u64 to usize let start = usize::try_from(line_start).ok()?; let end = usize::try_from(line_end).ok()?; @@ -193,7 +192,7 @@ unsafe fn parse_json(input: *const c_char) -> Result<Value, serde_json::Error> { serde_json::from_str(input_str) } -// Add this function to free the memory allocated by process_findings +// Free the string allocated by the `process_findings` function. Should be called after processing everything #[no_mangle] pub unsafe extern "C" fn free_string(ptr: *mut c_char) { if !ptr.is_null() {