Skip to content

Commit 39ae3c2

Browse files
committed
fixup! Add invalid null pointer usage lint.
1 parent 608ce34 commit 39ae3c2

File tree

1 file changed

+60
-51
lines changed

1 file changed

+60
-51
lines changed

clippy_lints/src/ptr.rs

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
44
use clippy_utils::ptr::get_spans;
55
use clippy_utils::source::snippet_opt;
66
use clippy_utils::ty::{is_type_diagnostic_item, match_type, walk_ptrs_hir_ty};
7-
use clippy_utils::{is_allowed, match_function_call, match_qpath, paths};
7+
use clippy_utils::{is_allowed, match_def_path, paths};
88
use if_chain::if_chain;
99
use rustc_errors::Applicability;
1010
use rustc_hir::{
@@ -174,7 +174,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
174174

175175
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
176176
if let ExprKind::Binary(ref op, l, r) = expr.kind {
177-
if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
177+
if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(cx, l) || is_null_path(cx, r)) {
178178
span_lint(
179179
cx,
180180
CMP_NULL,
@@ -188,47 +188,56 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
188188
}
189189
}
190190

191-
fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<()> {
192-
// fn_name, arg_idx
193-
const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], usize); 20] = [
194-
(&paths::SLICE_FROM_RAW_PARTS, 0),
195-
(&paths::SLICE_FROM_RAW_PARTS_MUT, 0),
196-
(&paths::PTR_COPY, 0),
197-
(&paths::PTR_COPY, 1),
198-
(&paths::PTR_COPY_NONOVERLAPPING, 0),
199-
(&paths::PTR_COPY_NONOVERLAPPING, 1),
200-
(&paths::PTR_READ, 0),
201-
(&paths::PTR_READ_UNALIGNED, 0),
202-
(&paths::PTR_READ_VOLATILE, 0),
203-
(&paths::PTR_REPLACE, 0),
204-
(&paths::PTR_SLICE_FROM_RAW_PARTS, 0),
205-
(&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, 0),
206-
(&paths::PTR_SWAP, 0),
207-
(&paths::PTR_SWAP, 1),
208-
(&paths::PTR_SWAP_NONOVERLAPPING, 0),
209-
(&paths::PTR_SWAP_NONOVERLAPPING, 1),
210-
(&paths::PTR_WRITE, 0),
211-
(&paths::PTR_WRITE_UNALIGNED, 0),
212-
(&paths::PTR_WRITE_VOLATILE, 0),
213-
(&paths::PTR_WRITE_BYTES, 0),
191+
fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
192+
// (fn_path, arg_idx, num_args) -
193+
// `arg_idx` is the `arg` position where null would cause U.B.
194+
// `num_args` is the numbers of arguments of the function
195+
const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], usize, usize); 20] = [
196+
(&paths::SLICE_FROM_RAW_PARTS, 0, 2),
197+
(&paths::SLICE_FROM_RAW_PARTS_MUT, 0, 2),
198+
(&paths::PTR_COPY, 0, 3),
199+
(&paths::PTR_COPY, 1, 3),
200+
(&paths::PTR_COPY_NONOVERLAPPING, 0, 3),
201+
(&paths::PTR_COPY_NONOVERLAPPING, 1, 3),
202+
(&paths::PTR_READ, 0, 1),
203+
(&paths::PTR_READ_UNALIGNED, 0, 1),
204+
(&paths::PTR_READ_VOLATILE, 0, 1),
205+
(&paths::PTR_REPLACE, 0, 2),
206+
(&paths::PTR_SLICE_FROM_RAW_PARTS, 0, 2),
207+
(&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, 0, 2),
208+
(&paths::PTR_SWAP, 0, 2),
209+
(&paths::PTR_SWAP, 1, 2),
210+
(&paths::PTR_SWAP_NONOVERLAPPING, 0, 3),
211+
(&paths::PTR_SWAP_NONOVERLAPPING, 1, 3),
212+
(&paths::PTR_WRITE, 0, 2),
213+
(&paths::PTR_WRITE_UNALIGNED, 0, 2),
214+
(&paths::PTR_WRITE_VOLATILE, 0, 2),
215+
(&paths::PTR_WRITE_BYTES, 0, 3),
214216
];
215217

216-
let arg = INVALID_NULL_PTR_USAGE_TABLE.iter().find_map(|(fn_name, arg_idx)| {
217-
let args = match_function_call(cx, expr, fn_name)?;
218-
args.get(*arg_idx).filter(|arg| is_null_path(arg))
219-
})?;
220-
221-
span_lint_and_sugg(
222-
cx,
223-
INVALID_NULL_PTR_USAGE,
224-
arg.span,
225-
"pointer must be non-null",
226-
"change this to",
227-
"core::ptr::NonNull::dangling().as_ptr()".to_string(),
228-
Applicability::MachineApplicable,
229-
);
230-
231-
Some(())
218+
for (fn_path, arg_idx, num_args) in &INVALID_NULL_PTR_USAGE_TABLE {
219+
if_chain! {
220+
if let ExprKind::Call(ref fun, ref args) = expr.kind;
221+
if args.len() == *num_args;
222+
if let ExprKind::Path(ref qpath) = fun.kind;
223+
if let Some(arg) = args.get(*arg_idx);
224+
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
225+
if match_def_path(cx, fun_def_id, fn_path);
226+
if is_null_path(cx, arg);
227+
then {
228+
span_lint_and_sugg(
229+
cx,
230+
INVALID_NULL_PTR_USAGE,
231+
arg.span,
232+
"pointer must be non-null",
233+
"change this to",
234+
"core::ptr::NonNull::dangling().as_ptr()".to_string(),
235+
Applicability::MachineApplicable,
236+
);
237+
return;
238+
}
239+
}
240+
}
232241
}
233242

234243
#[allow(clippy::too_many_lines)]
@@ -411,16 +420,16 @@ fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability,
411420
}
412421
}
413422

414-
fn is_null_path(expr: &Expr<'_>) -> bool {
415-
if let ExprKind::Call(pathexp, args) = expr.kind {
416-
if args.is_empty() {
417-
if let ExprKind::Path(ref path) = pathexp.kind {
418-
return match_qpath(path, &paths::PTR_NULL)
419-
|| match_qpath(path, &paths::PTR_NULL_MUT)
420-
|| match_qpath(path, &paths::STD_PTR_NULL)
421-
|| match_qpath(path, &paths::STD_PTR_NULL_MUT);
422-
}
423+
fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
424+
if_chain! {
425+
if let ExprKind::Call(path, args) = expr.kind;
426+
if args.is_empty();
427+
if let ExprKind::Path(ref qpath) = path.kind;
428+
if let Some(fn_def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
429+
then {
430+
match_def_path(cx, fn_def_id, &paths::PTR_NULL) || match_def_path(cx, fn_def_id, &paths::PTR_NULL_MUT)
431+
} else {
432+
false
423433
}
424434
}
425-
false
426435
}

0 commit comments

Comments
 (0)