Skip to content

Commit f637220

Browse files
committed
Add invalid null pointer usage lint.
1 parent 70ffebf commit f637220

File tree

8 files changed

+78
-3
lines changed

8 files changed

+78
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,7 @@ Released 2018-09-13
18721872
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
18731873
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
18741874
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
1875+
[`invalid_null_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_usage
18751876
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
18761877
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
18771878
[`invalid_upcast_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_upcast_comparisons

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
804804
&pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
805805
&precedence::PRECEDENCE,
806806
&ptr::CMP_NULL,
807+
&ptr::INVALID_NULL_USAGE,
807808
&ptr::MUT_FROM_REF,
808809
&ptr::PTR_ARG,
809810
&ptr_eq::PTR_EQ,
@@ -1511,6 +1512,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15111512
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
15121513
LintId::of(&precedence::PRECEDENCE),
15131514
LintId::of(&ptr::CMP_NULL),
1515+
LintId::of(&ptr::INVALID_NULL_USAGE),
15141516
LintId::of(&ptr::MUT_FROM_REF),
15151517
LintId::of(&ptr::PTR_ARG),
15161518
LintId::of(&ptr_eq::PTR_EQ),
@@ -1836,6 +1838,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
18361838
LintId::of(&mut_key::MUTABLE_KEY_TYPE),
18371839
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
18381840
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
1841+
LintId::of(&ptr::INVALID_NULL_USAGE),
18391842
LintId::of(&ptr::MUT_FROM_REF),
18401843
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
18411844
LintId::of(&regex::INVALID_REGEX),

clippy_lints/src/ptr.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
33
use crate::utils::ptr::get_spans;
44
use crate::utils::{
5-
is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
6-
span_lint_and_then, walk_ptrs_hir_ty,
5+
is_allowed, is_type_diagnostic_item, match_function_call, match_qpath, match_type, paths, snippet_opt, span_lint,
6+
span_lint_and_sugg, span_lint_and_then, walk_ptrs_hir_ty,
77
};
88
use if_chain::if_chain;
99
use rustc_errors::Applicability;
@@ -119,7 +119,28 @@ declare_clippy_lint! {
119119
"fns that create mutable refs from immutable ref args"
120120
}
121121

122-
declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);
122+
declare_clippy_lint! {
123+
/// **What it does:** This lint checks for invalid usages of `ptr::null`.
124+
///
125+
/// **Why is this bad?** This causes undefined behavior.
126+
///
127+
/// **Known problems:** None.
128+
///
129+
/// **Example:**
130+
/// ```ignore
131+
/// // Bad. Undefined behavior
132+
/// unsafe { std::slice::from_raw_parts(ptr::null(), 0); }
133+
/// ```
134+
///
135+
/// // Good
136+
/// unsafe { std::slice::from_raw_parts(NonNull::dangling().as_ptr(), 0); }
137+
/// ```
138+
pub INVALID_NULL_USAGE,
139+
correctness,
140+
"invalid usage of a null pointer, suggesting `NonNull::dangling()` instead."
141+
}
142+
143+
declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_USAGE]);
123144

124145
impl<'tcx> LateLintPass<'tcx> for Ptr {
125146
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -161,6 +182,20 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
161182
"comparing with null is better expressed by the `.is_null()` method",
162183
);
163184
}
185+
} else if let Some(args) = match_function_call(cx, expr, &paths::SLICE_FROM_RAW_PARTS) {
186+
if let Some(arg) = args.first() {
187+
if is_null_path(arg) {
188+
span_lint_and_sugg(
189+
cx,
190+
INVALID_NULL_USAGE,
191+
arg.span,
192+
"pointer must be non-null",
193+
"change this to",
194+
"core::ptr::NonNull::dangling().as_ptr()".to_string(),
195+
Applicability::MachineApplicable,
196+
);
197+
}
198+
}
164199
}
165200
}
166201
}

clippy_lints/src/utils/paths.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGu
114114
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
115115
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
116116
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
117+
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
117118
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
118119
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
119120
pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];

src/lintlist/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,13 @@ vec![
977977
deprecation: None,
978978
module: "atomic_ordering",
979979
},
980+
Lint {
981+
name: "invalid_null_usage",
982+
group: "correctness",
983+
desc: "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead.",
984+
deprecation: None,
985+
module: "ptr",
986+
},
980987
Lint {
981988
name: "invalid_regex",
982989
group: "correctness",

tests/ui/invalid_null_usage.fixed

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// run-rustfix
2+
3+
fn main() {
4+
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0) };
5+
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0) };
6+
}

tests/ui/invalid_null_usage.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// run-rustfix
2+
3+
fn main() {
4+
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(std::ptr::null(), 0) };
5+
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::null(), 0) };
6+
}

tests/ui/invalid_null_usage.stderr

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: pointer must be non-null
2+
--> $DIR/invalid_null_usage.rs:4:64
3+
|
4+
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts(std::ptr::null(), 0) };
5+
| ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
6+
|
7+
= note: `#[deny(clippy::invalid_null_usage)]` on by default
8+
9+
error: pointer must be non-null
10+
--> $DIR/invalid_null_usage.rs:5:64
11+
|
12+
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::null(), 0) };
13+
| ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
14+
15+
error: aborting due to 2 previous errors
16+

0 commit comments

Comments
 (0)