Skip to content

Commit 550c114

Browse files
committed
Add invalid null pointer usage lint.
1 parent 4e83a38 commit 550c114

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
@@ -1762,6 +1762,7 @@ Released 2018-09-13
17621762
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
17631763
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
17641764
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
1765+
[`invalid_null_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_usage
17651766
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
17661767
[`invalid_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_regex
17671768
[`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
@@ -780,6 +780,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
780780
&pattern_type_mismatch::PATTERN_TYPE_MISMATCH,
781781
&precedence::PRECEDENCE,
782782
&ptr::CMP_NULL,
783+
&ptr::INVALID_NULL_USAGE,
783784
&ptr::MUT_FROM_REF,
784785
&ptr::PTR_ARG,
785786
&ptr_eq::PTR_EQ,
@@ -1464,6 +1465,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
14641465
LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL),
14651466
LintId::of(&precedence::PRECEDENCE),
14661467
LintId::of(&ptr::CMP_NULL),
1468+
LintId::of(&ptr::INVALID_NULL_USAGE),
14671469
LintId::of(&ptr::MUT_FROM_REF),
14681470
LintId::of(&ptr::PTR_ARG),
14691471
LintId::of(&ptr_eq::PTR_EQ),
@@ -1775,6 +1777,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
17751777
LintId::of(&mut_key::MUTABLE_KEY_TYPE),
17761778
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
17771779
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
1780+
LintId::of(&ptr::INVALID_NULL_USAGE),
17781781
LintId::of(&ptr::MUT_FROM_REF),
17791782
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
17801783
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
@@ -107,6 +107,7 @@ pub const RWLOCK_READ_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockReadGu
107107
pub const RWLOCK_WRITE_GUARD: [&str; 4] = ["std", "sync", "rwlock", "RwLockWriteGuard"];
108108
pub const SERDE_DESERIALIZE: [&str; 2] = ["_serde", "Deserialize"];
109109
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
110+
pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
110111
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
111112
pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
112113
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
@@ -949,6 +949,13 @@ vec![
949949
deprecation: None,
950950
module: "atomic_ordering",
951951
},
952+
Lint {
953+
name: "invalid_null_usage",
954+
group: "correctness",
955+
desc: "invalid usage of a null pointer, suggesting `NonNull::dangling()` instead.",
956+
deprecation: None,
957+
module: "ptr",
958+
},
952959
Lint {
953960
name: "invalid_regex",
954961
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)