-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unsafe-block test case and detector (#38)
* Added unsafe-block test cases * Added unsafe-block detector --------- Co-authored-by: Agustín Losiggio <[email protected]>
- Loading branch information
1 parent
54bb7e2
commit 213ec36
Showing
9 changed files
with
255 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "avoid-unsafe-block" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
dylint_linting = { workspace = true } | ||
if_chain = { workspace = true } | ||
|
||
scout-audit-internal = { workspace = true } | ||
|
||
[dev-dependencies] | ||
dylint_testing = { workspace = true } | ||
|
||
[package.metadata.rust-analyzer] | ||
rustc_private = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#![feature(rustc_private)] | ||
|
||
extern crate rustc_ast; | ||
extern crate rustc_hir; | ||
extern crate rustc_span; | ||
|
||
use rustc_hir::{ | ||
intravisit::{walk_expr, Visitor}, | ||
Expr, ExprKind, | ||
}; | ||
use rustc_lint::LateLintPass; | ||
use rustc_span::Span; | ||
use scout_audit_internal::Detector; | ||
|
||
dylint_linting::declare_late_lint! { | ||
/// ### What it does | ||
/// Checks for usage of `unsafe` blocks. | ||
/// | ||
/// ### Why is this bad? | ||
/// `unsafe` blocks should not be used unless absolutely necessary. | ||
/// | ||
/// ### Example | ||
/// ```rust | ||
///pub fn unsafe_function(n: u64) -> u64 { | ||
/// unsafe { | ||
/// let mut i = n as f64; | ||
/// let mut y = i.to_bits(); | ||
/// y = 0x5fe6ec85e7de30da - (y >> 1); | ||
/// i = f64::from_bits(y); | ||
/// i *= 1.5 - 0.5 * n as f64 * i * i; | ||
/// i *= 1.5 - 0.5 * n as f64 * i * i; | ||
/// | ||
/// let result_ptr: *mut f64 = &mut i; | ||
/// let result = *result_ptr; | ||
/// | ||
/// result.to_bits() | ||
/// } | ||
///} | ||
/// Use instead: | ||
/// ```rust | ||
///pub fn unsafe_function(n: u64) -> u64 { | ||
/// let mut i = n as f64; | ||
/// let mut y = i.to_bits(); | ||
/// y = 0x5fe6ec85e7de30da - (y >> 1); | ||
/// i = f64::from_bits(y); | ||
/// i *= 1.5 - 0.5 * n as f64 * i * i; | ||
/// i *= 1.5 - 0.5 * n as f64 * i * i; | ||
/// result.to_bits() | ||
///} | ||
/// ``` | ||
pub AVOID_UNSAFE_BLOCK, | ||
Warn, | ||
Detector::AvoidUnsafeBlock.get_lint_message() | ||
} | ||
|
||
impl<'tcx> LateLintPass<'tcx> for AvoidUnsafeBlock { | ||
fn check_fn( | ||
&mut self, | ||
cx: &rustc_lint::LateContext<'tcx>, | ||
_: rustc_hir::intravisit::FnKind<'tcx>, | ||
_: &'tcx rustc_hir::FnDecl<'tcx>, | ||
body: &'tcx rustc_hir::Body<'tcx>, | ||
_: rustc_span::Span, | ||
_: rustc_hir::def_id::LocalDefId, | ||
) { | ||
struct UnsafeBlockVisitor { | ||
unsafe_blocks: Vec<Option<Span>>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for UnsafeBlockVisitor { | ||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { | ||
if let ExprKind::Block(block, _) = expr.kind { | ||
if block.rules | ||
== rustc_hir::BlockCheckMode::UnsafeBlock( | ||
rustc_hir::UnsafeSource::UserProvided, | ||
) | ||
{ | ||
self.unsafe_blocks.push(Some(expr.span)); | ||
} | ||
} | ||
|
||
walk_expr(self, expr); | ||
} | ||
} | ||
|
||
let mut visitor = UnsafeBlockVisitor { | ||
unsafe_blocks: Vec::new(), | ||
}; | ||
|
||
walk_expr(&mut visitor, body.value); | ||
|
||
visitor.unsafe_blocks.iter().for_each(|span| { | ||
if let Some(span) = span { | ||
Detector::AvoidUnsafeBlock.span_lint(cx, AVOID_UNSAFE_BLOCK, *span); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "avoid-unsafe-block-1-remediated" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
soroban-sdk = { version = "20.0.0" } | ||
|
||
[dev_dependencies] | ||
soroban-sdk = { version = "20.0.0", features = ["testutils"] } | ||
|
||
[features] | ||
testutils = ["soroban-sdk/testutils"] | ||
|
||
[profile.release] | ||
opt-level = "z" | ||
overflow-checks = true | ||
debug = 0 | ||
strip = "symbols" | ||
debug-assertions = false | ||
panic = "abort" | ||
codegen-units = 1 | ||
lto = true | ||
|
||
[profile.release-with-logs] | ||
inherits = "release" | ||
debug-assertions = true |
33 changes: 33 additions & 0 deletions
33
test-cases/avoid-unsafe-block/avoid-unsafe-block-1/remediated-example/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#![no_std] | ||
use soroban_sdk::{contract, contractimpl}; | ||
#[contract] | ||
pub struct AvoidUnsafeBlock; | ||
#[contractimpl] | ||
impl AvoidUnsafeBlock { | ||
pub fn unsafe_function(n: u64) -> u64 { | ||
let mut i = n as f64; | ||
let mut y = i.to_bits(); | ||
y = 0x5fe6ec85e7de30da - (y >> 1); | ||
i = f64::from_bits(y); | ||
i *= 1.5 - 0.5 * n as f64 * i * i; | ||
i *= 1.5 - 0.5 * n as f64 * i * i; | ||
i.to_bits() | ||
} | ||
} | ||
#[cfg(test)] | ||
mod tests { | ||
use crate::AvoidUnsafeBlock; | ||
#[test] | ||
fn test_unsafe_block() { | ||
let test_value = 8; | ||
let result = AvoidUnsafeBlock::unsafe_function(test_value); | ||
let inverse = inverse_square_root_without_unsafe(test_value); | ||
|
||
assert_eq!((inverse - result) / inverse, 0); | ||
assert_eq!((inverse - result) / result, 0); | ||
} | ||
|
||
fn inverse_square_root_without_unsafe(n: u64) -> u64 { | ||
(1.0 / (n as f64).sqrt()).to_bits() | ||
} | ||
} |
30 changes: 30 additions & 0 deletions
30
test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/Cargo.toml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "avoid-unsafe-block-1-vulnerable" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[lib] | ||
crate-type = ["cdylib"] | ||
|
||
[dependencies] | ||
soroban-sdk = { version = "20.0.0" } | ||
|
||
[dev_dependencies] | ||
soroban-sdk = { version = "20.0.0", features = ["testutils"] } | ||
|
||
[features] | ||
testutils = ["soroban-sdk/testutils"] | ||
|
||
[profile.release] | ||
opt-level = "z" | ||
overflow-checks = true | ||
debug = 0 | ||
strip = "symbols" | ||
debug-assertions = false | ||
panic = "abort" | ||
codegen-units = 1 | ||
lto = true | ||
|
||
[profile.release-with-logs] | ||
inherits = "release" | ||
debug-assertions = true |
38 changes: 38 additions & 0 deletions
38
test-cases/avoid-unsafe-block/avoid-unsafe-block-1/vulnerable-example/src/lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#![no_std] | ||
use soroban_sdk::{contract, contractimpl}; | ||
#[contract] | ||
pub struct AvoidUnsafeBlock; | ||
#[contractimpl] | ||
impl AvoidUnsafeBlock { | ||
pub fn unsafe_function(n: u64) -> u64 { | ||
unsafe { | ||
let mut i = n as f64; | ||
let mut y = i.to_bits(); | ||
y = 0x5fe6ec85e7de30da - (y >> 1); | ||
i = f64::from_bits(y); | ||
i *= 1.5 - 0.5 * n as f64 * i * i; | ||
i *= 1.5 - 0.5 * n as f64 * i * i; | ||
|
||
let result_ptr: *mut f64 = &mut i; | ||
|
||
(*result_ptr).to_bits() | ||
} | ||
} | ||
} | ||
#[cfg(test)] | ||
mod tests { | ||
use crate::AvoidUnsafeBlock; | ||
#[test] | ||
fn test_unsafe_block() { | ||
let test_value = 8; | ||
let result = AvoidUnsafeBlock::unsafe_function(test_value); | ||
let inverse = inverse_square_root_without_unsafe(test_value); | ||
|
||
assert_eq!((inverse - result) / inverse, 0); | ||
assert_eq!((inverse - result) / result, 0); | ||
} | ||
|
||
fn inverse_square_root_without_unsafe(n: u64) -> u64 { | ||
(1.0 / (n as f64).sqrt()).to_bits() | ||
} | ||
} |