Skip to content

Commit

Permalink
Add invalid null pointer usage lint.
Browse files Browse the repository at this point in the history
  • Loading branch information
boxdot committed Oct 18, 2020
1 parent 4e83a38 commit 550c114
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,7 @@ Released 2018-09-13
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
[`invalid_null_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_usage
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons
Expand Down
3 changes: 3 additions & 0 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
&precedence::PRECEDENCE,
&ptr::CMP_NULL,
&ptr::INVALID_NULL_USAGE,
&ptr::MUT_FROM_REF,
&ptr::PTR_ARG,
&ptr_eq::PTR_EQ,
Expand Down Expand Up @@ -1464,6 +1465,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
LintId::of(&precedence::PRECEDENCE),
LintId::of(&ptr::CMP_NULL),
LintId::of(&ptr::INVALID_NULL_USAGE),
LintId::of(&ptr::MUT_FROM_REF),
LintId::of(&ptr::PTR_ARG),
LintId::of(&ptr_eq::PTR_EQ),
Expand Down Expand Up @@ -1775,6 +1777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&mut_key::MUTABLE_KEY_TYPE),
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(&ptr::INVALID_NULL_USAGE),
LintId::of(&ptr::MUT_FROM_REF),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&regex::INVALID_REGEX),
Expand Down
41 changes: 38 additions & 3 deletions clippy_lints/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
use crate::utils::ptr::get_spans;
use crate::utils::{
is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
span_lint_and_then, walk_ptrs_hir_ty,
is_allowed, is_type_diagnostic_item, match_function_call, match_qpath, match_type, paths, snippet_opt, span_lint,
span_lint_and_sugg, span_lint_and_then, walk_ptrs_hir_ty,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
Expand Down Expand Up @@ -119,7 +119,28 @@ declare_clippy_lint! {
"fns that create mutable refs from immutable ref args"
}

declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);
declare_clippy_lint! {
/// **What it does:** This lint checks for invalid usages of `ptr::null`.
///
/// **Why is this bad?** This causes undefined behavior.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```ignore
/// // Bad. Undefined behavior
/// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
/// ```
///
/// // Good
/// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
/// ```
pub INVALID_NULL_USAGE,
correctness,
"invalid usage of a null pointer, suggesting `NonNull::dangling()` instead."
}

declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_USAGE]);

impl<'tcx> LateLintPass<'tcx> for Ptr {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
Expand Down Expand Up @@ -161,6 +182,20 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
"comparing with null is better expressed by the `.is_null()` method",
);
}
} else if let Some(args) = match_function_call(cx, expr, &paths::SLICE_FROM_RAW_PARTS) {
if let Some(arg) = args.first() {
if is_null_path(arg) {
span_lint_and_sugg(
cx,
INVALID_NULL_USAGE,
arg.span,
"pointer must be non-null",
"change this to",
"core::ptr::NonNull::dangling().as_ptr()".to_string(),
Applicability::MachineApplicable,
);
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions clippy_lints/src/utils/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGu
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
Expand Down
7 changes: 7 additions & 0 deletions src/lintlist/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,13 @@ vec![
deprecation: None,
module: "atomic_ordering",
},
Lint {
name: "invalid_null_usage",
group: "correctness",
desc: "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead.",
deprecation: None,
module: "ptr",
},
Lint {
name: "invalid_regex",
group: "correctness",
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/invalid_null_usage.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// run-rustfix

fn main() {
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0) };
}
6 changes: 6 additions & 0 deletions tests/ui/invalid_null_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// run-rustfix

fn main() {
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(std::ptr::null(), 0) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::null(), 0) };
}
16 changes: 16 additions & 0 deletions tests/ui/invalid_null_usage.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
error: pointer must be non-null
--> $DIR/invalid_null_usage.rs:4:64
|
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts(std::ptr::null(), 0) };
| ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
|
= note: `#[deny(clippy::invalid_null_usage)]` on by default

error: pointer must be non-null
--> $DIR/invalid_null_usage.rs:5:64
|
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::null(), 0) };
| ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: aborting due to 2 previous errors

0 comments on commit 550c114

Please sign in to comment.