Skip to content

Commit

Permalink
Add remaining functions from std::ptr.
Browse files Browse the repository at this point in the history
  • Loading branch information
boxdot committed Nov 23, 2020
1 parent 6e28b00 commit 302d171
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 51 deletions.
68 changes: 48 additions & 20 deletions clippy_lints/src/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,6 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
}

fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
const INVALID_NULL_PTR_USAGE_FNS: [&[&'static str]; 2] =
[&paths::SLICE_FROM_RAW_PARTS, &paths::SLICE_FROM_RAW_PARTS_MUT];

if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind {
if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
span_lint(
Expand All @@ -185,27 +182,58 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
"comparing with null is better expressed by the `.is_null()` method",
);
}
} else if let Some(arg) = INVALID_NULL_PTR_USAGE_FNS
.iter()
.filter_map(|fn_name| match_function_call(cx, expr, fn_name))
.next()
.and_then(|args| args.first())
{
if is_null_path(arg) {
span_lint_and_sugg(
cx,
INVALID_NULL_PTR_USAGE,
arg.span,
"pointer must be non-null",
"change this to",
"core::ptr::NonNull::dangling().as_ptr()".to_string(),
Applicability::MachineApplicable,
);
}
} else {
check_invalid_ptr_usage(cx, expr);
}
}
}

fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<()> {
// fn_name, arg_idx
const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], usize); 20] = [
(&paths::SLICE_FROM_RAW_PARTS, 0),
(&paths::SLICE_FROM_RAW_PARTS_MUT, 0),
(&paths::PTR_COPY, 0),
(&paths::PTR_COPY, 1),
(&paths::PTR_COPY_NONOVERLAPPING, 0),
(&paths::PTR_COPY_NONOVERLAPPING, 1),
(&paths::PTR_READ, 0),
(&paths::PTR_READ_UNALIGNED, 0),
(&paths::PTR_READ_VOLATILE, 0),
(&paths::PTR_REPLACE, 0),
(&paths::PTR_SLICE_FROM_RAW_PARTS, 0),
(&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, 0),
(&paths::PTR_SWAP, 0),
(&paths::PTR_SWAP, 1),
(&paths::PTR_SWAP_NONOVERLAPPING, 0),
(&paths::PTR_SWAP_NONOVERLAPPING, 1),
(&paths::PTR_WRITE, 0),
(&paths::PTR_WRITE_UNALIGNED, 0),
(&paths::PTR_WRITE_VOLATILE, 0),
(&paths::PTR_WRITE_BYTES, 0),
];

let arg = INVALID_NULL_PTR_USAGE_TABLE
.iter()
.filter_map(|(fn_name, arg_idx)| {
let args = match_function_call(cx, expr, fn_name)?;
args.iter().nth(*arg_idx).filter(|arg| is_null_path(arg))
})
.next()?;

span_lint_and_sugg(
cx,
INVALID_NULL_PTR_USAGE,
arg.span,
"pointer must be non-null",
"change this to",
format!("core::ptr::NonNull::dangling().as_ptr()"),
Applicability::MachineApplicable,
);

Some(())
}

#[allow(clippy::too_many_lines)]
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
Expand Down
14 changes: 14 additions & 0 deletions clippy_lints/src/utils/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,23 @@ pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
pub const PTR_COPY: [&str; 3] = ["core", "ptr", "copy"];
pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "copy_nonoverlapping"];
pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"];
pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"];
pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"];
pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"];
pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"];
pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"];
pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"];
pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"];
pub const PTR_WRITE: [&str; 3] = ["core", "ptr", "write"];
pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
pub const PTR_WRITE_UNALIGNED: [&str; 3] = ["core", "ptr", "write_unaligned"];
pub const PTR_WRITE_VOLATILE: [&str; 3] = ["core", "ptr", "write_volatile"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
Expand Down
50 changes: 44 additions & 6 deletions tests/ui/invalid_null_ptr_usage.fixed
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
// 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) };
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) };
unsafe {
let _slice: &[usize] = std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);
let _slice: &[usize] = std::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);

let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0) };
let _slice: &[usize] = std::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0);

std::ptr::copy::<usize>(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0);
std::ptr::copy::<usize>(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0);

std::ptr::copy_nonoverlapping::<usize>(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0);
std::ptr::copy_nonoverlapping::<usize>(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0);

struct A; // zero sized struct
assert_eq!(std::mem::size_of::<A>(), 0);

let _a: A = std::ptr::read(core::ptr::NonNull::dangling().as_ptr());
let _a: A = std::ptr::read(core::ptr::NonNull::dangling().as_ptr());

let _a: A = std::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr());
let _a: A = std::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr());

let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr());
let _a: A = std::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr());

let _a: A = std::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A);

let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);
let _slice: *const [usize] = std::ptr::slice_from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0);

let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0);

std::ptr::swap::<A>(core::ptr::NonNull::dangling().as_ptr(), &mut A);
std::ptr::swap::<A>(&mut A, core::ptr::NonNull::dangling().as_ptr());

std::ptr::swap_nonoverlapping::<A>(core::ptr::NonNull::dangling().as_ptr(), &mut A, 0);
std::ptr::swap_nonoverlapping::<A>(&mut A, core::ptr::NonNull::dangling().as_ptr(), 0);

std::ptr::write(core::ptr::NonNull::dangling().as_ptr(), A);

std::ptr::write_unaligned(core::ptr::NonNull::dangling().as_ptr(), A);

std::ptr::write_volatile(core::ptr::NonNull::dangling().as_ptr(), A);

std::ptr::write_bytes::<usize>(core::ptr::NonNull::dangling().as_ptr(), 42, 0);
}
}
50 changes: 44 additions & 6 deletions tests/ui/invalid_null_ptr_usage.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,49 @@
// 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) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(std::ptr::null_mut(), 0) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts(core::ptr::null_mut(), 0) };
unsafe {
let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), 0);
let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0);

let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0) };
let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(core::ptr::null_mut(), 0) };
let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0);

std::ptr::copy::<usize>(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0);
std::ptr::copy::<usize>(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0);

std::ptr::copy_nonoverlapping::<usize>(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0);
std::ptr::copy_nonoverlapping::<usize>(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0);

struct A; // zero sized struct
assert_eq!(std::mem::size_of::<A>(), 0);

let _a: A = std::ptr::read(std::ptr::null());
let _a: A = std::ptr::read(std::ptr::null_mut());

let _a: A = std::ptr::read_unaligned(std::ptr::null());
let _a: A = std::ptr::read_unaligned(std::ptr::null_mut());

let _a: A = std::ptr::read_volatile(std::ptr::null());
let _a: A = std::ptr::read_volatile(std::ptr::null_mut());

let _a: A = std::ptr::replace(std::ptr::null_mut(), A);

let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0);

let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0);

std::ptr::swap::<A>(std::ptr::null_mut(), &mut A);
std::ptr::swap::<A>(&mut A, std::ptr::null_mut());

std::ptr::swap_nonoverlapping::<A>(std::ptr::null_mut(), &mut A, 0);
std::ptr::swap_nonoverlapping::<A>(&mut A, std::ptr::null_mut(), 0);

std::ptr::write(std::ptr::null_mut(), A);

std::ptr::write_unaligned(std::ptr::null_mut(), A);

std::ptr::write_volatile(std::ptr::null_mut(), A);

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

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

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

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

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:9:68
--> $DIR/invalid_null_ptr_usage.rs:20:36
|
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0) };
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
LL | let _a: A = std::ptr::read(std::ptr::null_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:10:68
--> $DIR/invalid_null_ptr_usage.rs:22:46
|
LL | let _slice: &[usize] = unsafe { std::slice::from_raw_parts_mut(core::ptr::null_mut(), 0) };
| ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`
LL | let _a: A = std::ptr::read_unaligned(std::ptr::null());
| ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: aborting due to 6 previous errors
error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:23:46
|
LL | let _a: A = std::ptr::read_unaligned(std::ptr::null_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:25:45
|
LL | let _a: A = std::ptr::read_volatile(std::ptr::null());
| ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:26:45
|
LL | let _a: A = std::ptr::read_volatile(std::ptr::null_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:28:39
|
LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:30:69
|
LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null(), 0);
| ^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:31:69
|
LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:33:73
|
LL | let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:35:29
|
LL | std::ptr::swap::<A>(std::ptr::null_mut(), &mut A);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:36:37
|
LL | std::ptr::swap::<A>(&mut A, std::ptr::null_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:38:44
|
LL | std::ptr::swap_nonoverlapping::<A>(std::ptr::null_mut(), &mut A, 0);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:39:52
|
LL | std::ptr::swap_nonoverlapping::<A>(&mut A, std::ptr::null_mut(), 0);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:41:25
|
LL | std::ptr::write(std::ptr::null_mut(), A);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:43:35
|
LL | std::ptr::write_unaligned(std::ptr::null_mut(), A);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:45:34
|
LL | std::ptr::write_volatile(std::ptr::null_mut(), A);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: pointer must be non-null
--> $DIR/invalid_null_ptr_usage.rs:47:40
|
LL | std::ptr::write_bytes::<usize>(std::ptr::null_mut(), 42, 0);
| ^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()`

error: aborting due to 21 previous errors

0 comments on commit 302d171

Please sign in to comment.