From b6113066429bc3108f62b920ccbfc79accfef2dd Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Nov 2020 22:44:02 -0300 Subject: [PATCH 1/6] Add lint unsafe_sizeof_count_copies --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 + .../src/unsafe_sizeof_count_copies.rs | 98 +++++++++++++ clippy_lints/src/utils/paths.rs | 4 + tests/ui/unsafe_sizeof_count_copies.rs | 54 ++++++++ tests/ui/unsafe_sizeof_count_copies.stderr | 131 ++++++++++++++++++ 6 files changed, 293 insertions(+) create mode 100644 clippy_lints/src/unsafe_sizeof_count_copies.rs create mode 100644 tests/ui/unsafe_sizeof_count_copies.rs create mode 100644 tests/ui/unsafe_sizeof_count_copies.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e65e7cc639f..e0f3b82ad25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2124,6 +2124,7 @@ Released 2018-09-13 [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name +[`unsafe_sizeof_count_copies`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_sizeof_count_copies [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 167e5b6b87f..1bce0130b40 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -329,6 +329,7 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; +mod unsafe_sizeof_count_copies; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -916,6 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + &unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -998,6 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_late_pass(|| box unsafe_sizeof_count_copies::UnsafeSizeofCountCopies); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -1605,6 +1608,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), + LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1883,6 +1887,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), + LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs new file mode 100644 index 00000000000..2422df8feba --- /dev/null +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -0,0 +1,98 @@ +//! Lint on unsafe memory copying that use the `size_of` of the pointee type instead of a pointee +//! count + +use crate::utils::{match_def_path, paths, span_lint_and_help}; +use if_chain::if_chain; +use rustc_hir::BinOpKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{Ty as TyM, TyS}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** Detects expressions where + /// size_of:: is used as the count argument to unsafe + /// memory copying functions like ptr::copy and + /// ptr::copy_nonoverlapping where T is the pointee type + /// of the pointers used + /// + /// **Why is this bad?** These functions expect a count + /// of T and not a number of bytes, which can lead to + /// copying the incorrect amount of bytes, which can + /// result in Undefined Behaviour + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust,no_run + /// # use std::ptr::copy_nonoverlapping; + /// # use std::mem::size_of; + /// + /// const SIZE: usize = 128; + /// let x = [2u8; SIZE]; + /// let mut y = [2u8; SIZE]; + /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + /// ``` + pub UNSAFE_SIZEOF_COUNT_COPIES, + correctness, + "unsafe memory copying using a byte count instead of a count of T" +} + +declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); + +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { + match &expr.kind { + ExprKind::Call(ref count_func, _func_args) => { + if_chain! { + if let ExprKind::Path(ref count_func_qpath) = count_func.kind; + if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::MEM_SIZE_OF) + || match_def_path(cx, def_id, &paths::MEM_SIZE_OF_VAL); + then { + cx.typeck_results().node_substs(count_func.hir_id).types().next() + } else { + None + } + } + }, + ExprKind::Binary(op, left, right) if BinOpKind::Mul == op.node || BinOpKind::Div == op.node => { + get_size_of_ty(cx, &*left).or_else(|| get_size_of_ty(cx, &*right)) + }, + _ => None, + } +} + +impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(ref func, ref func_args) = expr.kind; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) + || match_def_path(cx, def_id, &paths::COPY); + + // Get the pointee type + let _substs = cx.typeck_results().node_substs(func.hir_id); + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + + // Find a size_of call in the count parameter expression and + // check that it's the same type + if let [_src, _dest, count] = &**func_args; + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count); + if TyS::same_type(pointee_ty, ty_used_for_size_of); + then { + span_lint_and_help( + cx, + UNSAFE_SIZEOF_COUNT_COPIES, + expr.span, + "unsafe memory copying using a byte count (Multiplied by size_of::) \ + instead of a count of T", + None, + "use a count of elements instead of a count of bytes for the count parameter, \ + it already gets multiplied by the size of the pointed to type" + ); + } + }; + } +} diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 16e6a016c9e..fe763d4bfbb 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -20,6 +20,8 @@ pub const CLONE_TRAIT: [&str; 3] = ["core", "clone", "Clone"]; pub const CLONE_TRAIT_METHOD: [&str; 4] = ["core", "clone", "Clone", "clone"]; pub const CMP_MAX: [&str; 3] = ["core", "cmp", "max"]; pub const CMP_MIN: [&str; 3] = ["core", "cmp", "min"]; +pub const COPY: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"]; +pub const COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy"]; pub const COW: [&str; 3] = ["alloc", "borrow", "Cow"]; pub const CSTRING_AS_C_STR: [&str; 5] = ["std", "ffi", "c_str", "CString", "as_c_str"]; pub const DEFAULT_TRAIT: [&str; 3] = ["core", "default", "Default"]; @@ -73,6 +75,8 @@ pub const MEM_MANUALLY_DROP: [&str; 4] = ["core", "mem", "manually_drop", "Manua pub const MEM_MAYBEUNINIT: [&str; 4] = ["core", "mem", "maybe_uninit", "MaybeUninit"]; pub const MEM_MAYBEUNINIT_UNINIT: [&str; 5] = ["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]; pub const MEM_REPLACE: [&str; 3] = ["core", "mem", "replace"]; +pub const MEM_SIZE_OF: [&str; 3] = ["core", "mem", "size_of"]; +pub const MEM_SIZE_OF_VAL: [&str; 3] = ["core", "mem", "size_of_val"]; pub const MUTEX_GUARD: [&str; 4] = ["std", "sync", "mutex", "MutexGuard"]; pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"]; pub const OPS_MODULE: [&str; 2] = ["core", "ops"]; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs new file mode 100644 index 00000000000..0077ed07fce --- /dev/null +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -0,0 +1,54 @@ +#![warn(clippy::unsafe_sizeof_count_copies)] + +use std::mem::{size_of, size_of_val}; +use std::ptr::{copy, copy_nonoverlapping}; + +fn main() { + const SIZE: usize = 128; + const HALF_SIZE: usize = SIZE / 2; + const DOUBLE_SIZE: usize = SIZE * 2; + let mut x = [2u8; SIZE]; + let mut y = [2u8; SIZE]; + + // Count is size_of (Should trigger the lint) + unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + + // Count expression involving multiplication of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + + // Count expression involving nested multiplications of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; + + // Count expression involving divisions of size_of (Should trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; + + // No size_of calls (Should not trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; + + // Different types for pointee and size_of (Should not trigger the lint) + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; + + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; +} diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr new file mode 100644 index 00000000000..6804df8cdfc --- /dev/null +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -0,0 +1,131 @@ +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:14:14 + | +LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:15:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:17:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:21:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:24:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:25:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:29:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:31:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:35:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:38:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:39:14 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: aborting due to 16 previous errors + From 0f954babef41b16e26b900d3858ceac4005a4506 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 01:47:32 -0300 Subject: [PATCH 2/6] Make the unsafe_sizeof_count_copies lint find copy_{from,to} method calls --- .../src/unsafe_sizeof_count_copies.rs | 66 ++++++++++++++----- tests/ui/unsafe_sizeof_count_copies.rs | 5 ++ tests/ui/unsafe_sizeof_count_copies.stderr | 60 +++++++++++++---- 3 files changed, 99 insertions(+), 32 deletions(-) diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs index 2422df8feba..5df7d72564e 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -6,7 +6,7 @@ use if_chain::if_chain; use rustc_hir::BinOpKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{Ty as TyM, TyS}; +use rustc_middle::ty::{self, Ty, TyS, TypeAndMut}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -40,7 +40,7 @@ declare_clippy_lint! { declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); -fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { +fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { match &expr.kind { ExprKind::Call(ref count_func, _func_args) => { if_chain! { @@ -62,35 +62,65 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let [_src, _dest, count] = &**args; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) + || match_def_path(cx, def_id, &paths::COPY); + + // Get the pointee type + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + then { + return Some((pointee_ty, count)); + } + }; + if_chain! { + // Find calls to copy_{from,to}{,_nonoverlapping} + if let ExprKind::MethodCall(ref method_path, _, ref args, _) = expr.kind; + if let [ptr_self, _, count] = &**args; + let method_ident = method_path.ident.as_str(); + if method_ident== "copy_to" || method_ident == "copy_from" + || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; + + // Get the pointee type + if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = + cx.typeck_results().expr_ty(ptr_self).kind(); + then { + return Some((pointee_ty, count)); + } + }; + None +} + impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(ref func, ref func_args) = expr.kind; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY); + const HELP_MSG: &str = "use a count of elements instead of a count of bytes \ + for the count parameter, it already gets multiplied by the size of the pointed to type"; - // Get the pointee type - let _substs = cx.typeck_results().node_substs(func.hir_id); - if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + const LINT_MSG: &str = "unsafe memory copying using a byte count \ + (Multiplied by size_of::) instead of a count of T"; + + if_chain! { + // Find calls to unsafe copy functions and get + // the pointee type and count parameter expression + if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); // Find a size_of call in the count parameter expression and // check that it's the same type - if let [_src, _dest, count] = &**func_args; - if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count); + if let Some(ty_used_for_size_of) = get_size_of_ty(cx, count_expr); if TyS::same_type(pointee_ty, ty_used_for_size_of); then { span_lint_and_help( cx, UNSAFE_SIZEOF_COUNT_COPIES, expr.span, - "unsafe memory copying using a byte count (Multiplied by size_of::) \ - instead of a count of T", + LINT_MSG, None, - "use a count of elements instead of a count of bytes for the count parameter, \ - it already gets multiplied by the size of the pointed to type" + HELP_MSG ); } }; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 0077ed07fce..0bb22314cc0 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -14,6 +14,11 @@ fn main() { unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 6804df8cdfc..14ca04617c2 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -18,13 +18,45 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T --> $DIR/unsafe_sizeof_count_copies.rs:17:14 | +LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + | +LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:19:14 + | +LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:20:14 + | +LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:18:14 + --> $DIR/unsafe_sizeof_count_copies.rs:23:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +64,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:21:14 + --> $DIR/unsafe_sizeof_count_copies.rs:26:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +72,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 + --> $DIR/unsafe_sizeof_count_copies.rs:27:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +80,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:24:14 + --> $DIR/unsafe_sizeof_count_copies.rs:29:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +88,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:25:14 + --> $DIR/unsafe_sizeof_count_copies.rs:30:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +96,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + --> $DIR/unsafe_sizeof_count_copies.rs:33:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +104,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:29:14 + --> $DIR/unsafe_sizeof_count_copies.rs:34:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +112,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:31:14 + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +120,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + --> $DIR/unsafe_sizeof_count_copies.rs:37:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +128,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZ = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:35:14 + --> $DIR/unsafe_sizeof_count_copies.rs:40:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +136,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 + --> $DIR/unsafe_sizeof_count_copies.rs:41:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +144,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:38:14 + --> $DIR/unsafe_sizeof_count_copies.rs:43:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +152,12 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:39:14 + --> $DIR/unsafe_sizeof_count_copies.rs:44:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors From 1b80990fe01646868f85245f608203e23f64184a Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 14:23:59 -0300 Subject: [PATCH 3/6] Make the unsafe_sizeof_count_copies lint work with more functions Specifically: - find std::ptr::write_bytes - find std::ptr::swap_nonoverlapping - find std::ptr::slice_from_raw_parts - find std::ptr::slice_from_raw_parts_mut - pointer_primitive::write_bytes --- .../src/unsafe_sizeof_count_copies.rs | 42 ++++-- clippy_lints/src/utils/paths.rs | 4 + tests/ui/unsafe_sizeof_count_copies.rs | 12 +- tests/ui/unsafe_sizeof_count_copies.stderr | 122 ++++++++++++------ 4 files changed, 126 insertions(+), 54 deletions(-) diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/unsafe_sizeof_count_copies.rs index 5df7d72564e..8a4538091e7 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/unsafe_sizeof_count_copies.rs @@ -41,8 +41,8 @@ declare_clippy_lint! { declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { - match &expr.kind { - ExprKind::Call(ref count_func, _func_args) => { + match expr.kind { + ExprKind::Call(count_func, _func_args) => { if_chain! { if let ExprKind::Path(ref count_func_qpath) = count_func.kind; if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id(); @@ -56,7 +56,7 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { - get_size_of_ty(cx, &*left).or_else(|| get_size_of_ty(cx, &*right)) + get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) }, _ => None, } @@ -64,13 +64,16 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(ref func, ref args) = expr.kind; - if let [_src, _dest, count] = &**args; + // Find calls to ptr::{copy, copy_nonoverlapping} + // and ptr::{swap_nonoverlapping, write_bytes}, + if let ExprKind::Call(func, args) = expr.kind; + if let [_, _, count] = args; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY); + || match_def_path(cx, def_id, &paths::COPY) + || match_def_path(cx, def_id, &paths::WRITE_BYTES) + || match_def_path(cx, def_id, &paths::PTR_SWAP_NONOVERLAPPING); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); @@ -79,11 +82,11 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - } }; if_chain! { - // Find calls to copy_{from,to}{,_nonoverlapping} - if let ExprKind::MethodCall(ref method_path, _, ref args, _) = expr.kind; - if let [ptr_self, _, count] = &**args; + // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods + if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; + if let [ptr_self, _, count] = args; let method_ident = method_path.ident.as_str(); - if method_ident== "copy_to" || method_ident == "copy_from" + if method_ident == "write_bytes" || method_ident == "copy_to" || method_ident == "copy_from" || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; // Get the pointee type @@ -93,6 +96,21 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - return Some((pointee_ty, count)); } }; + if_chain! { + // Find calls to ptr::copy and copy_nonoverlapping + if let ExprKind::Call(func, args) = expr.kind; + if let [_data, count] = args; + if let ExprKind::Path(ref func_qpath) = func.kind; + if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS) + || match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS_MUT); + + // Get the pointee type + if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); + then { + return Some((pointee_ty, count)); + } + }; None } @@ -102,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { for the count parameter, it already gets multiplied by the size of the pointed to type"; const LINT_MSG: &str = "unsafe memory copying using a byte count \ - (Multiplied by size_of::) instead of a count of T"; + (multiplied by size_of/size_of_val::) instead of a count of T"; if_chain! { // Find calls to unsafe copy functions and get diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index fe763d4bfbb..87c020a99db 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -104,6 +104,9 @@ pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"]; 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_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_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"]; 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"]; @@ -158,3 +161,4 @@ pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"]; pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; +pub const WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"]; diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 0bb22314cc0..6aed8c31f7e 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -1,7 +1,9 @@ #![warn(clippy::unsafe_sizeof_count_copies)] use std::mem::{size_of, size_of_val}; -use std::ptr::{copy, copy_nonoverlapping}; +use std::ptr::{ + copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, +}; fn main() { const SIZE: usize = 128; @@ -22,6 +24,14 @@ fn main() { unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + + unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + + unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 14ca04617c2..6f491bc4e4a 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -1,5 +1,5 @@ -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:14:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:16:14 | LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,157 +7,197 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of: = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:15:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:17:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:17:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:19:14 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:18:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:20:14 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:19:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:21:14 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:20:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:22:14 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:24:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:23:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:25:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:26:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:27:14 + | +LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:28:14 + | +LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:30:14 + | +LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:32:14 + | +LL | unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:33:14 + | +LL | unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type + +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:36:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:27:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:37:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:29:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:39:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:30:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:40:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:33:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:43:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:34:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:44:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:46:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:37:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:47:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:40:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:50:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:41:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:51:14 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:43:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:53:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (Multiplied by size_of::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:44:14 +error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T + --> $DIR/unsafe_sizeof_count_copies.rs:54:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: aborting due to 20 previous errors +error: aborting due to 25 previous errors From 63a3c44060b9b06e10e7a854abcdbb853f6938c3 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 29 Nov 2020 14:32:11 -0300 Subject: [PATCH 4/6] Remove unnecessary unsafe_size_count_copies tests --- tests/ui/unsafe_sizeof_count_copies.rs | 22 +------ tests/ui/unsafe_sizeof_count_copies.stderr | 76 +--------------------- 2 files changed, 3 insertions(+), 95 deletions(-) diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/unsafe_sizeof_count_copies.rs index 6aed8c31f7e..2a9adeb6bd9 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/unsafe_sizeof_count_copies.rs @@ -34,36 +34,16 @@ fn main() { // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; // Count expression involving nested multiplications of size_of (Should trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; - // Count expression involving divisions of size_of (Should trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; // No size_of calls (Should not trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; // Different types for pointee and size_of (Should not trigger the lint) - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; - unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; - - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() / 2 * SIZE) }; - unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&0u16) / 2 * SIZE) }; + unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() / 2 * SIZE) }; } diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr index 6f491bc4e4a..7989e96dd21 100644 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ b/tests/ui/unsafe_sizeof_count_copies.stderr @@ -111,93 +111,21 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:37:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T --> $DIR/unsafe_sizeof_count_copies.rs:39:14 | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:40:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:43:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * HALF_SIZE * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:44:14 - | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:46:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE * HALF_SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:47:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * HALF_SIZE * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:50:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * DOUBLE_SIZE / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:51:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / 2 * size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:53:14 + --> $DIR/unsafe_sizeof_count_copies.rs:42:14 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:54:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0]) * DOUBLE_SIZE / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: aborting due to 25 previous errors +error: aborting due to 16 previous errors From af9685bb1e7e27a7b21d9939a42c1e9dce8c4df5 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 3 Dec 2020 20:55:38 -0300 Subject: [PATCH 5/6] Rename unsafe_sizeof_count_copies to size_of_in_element_count Also fix review comments: - Use const arrays and iterate them for the method/function names - merge 2 if_chain's into one using a rest pattern - remove unnecessary unsafe block in test And make the lint only point to the count expression instead of the entire function call --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 10 +- ..._copies.rs => size_of_in_element_count.rs} | 74 +++++----- ..._copies.rs => size_of_in_element_count.rs} | 9 +- tests/ui/size_of_in_element_count.stderr | 131 ++++++++++++++++++ tests/ui/unsafe_sizeof_count_copies.stderr | 131 ------------------ 6 files changed, 175 insertions(+), 182 deletions(-) rename clippy_lints/src/{unsafe_sizeof_count_copies.rs => size_of_in_element_count.rs} (63%) rename tests/ui/{unsafe_sizeof_count_copies.rs => size_of_in_element_count.rs} (86%) create mode 100644 tests/ui/size_of_in_element_count.stderr delete mode 100644 tests/ui/unsafe_sizeof_count_copies.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e0f3b82ad25..c7e02aaf4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2057,6 +2057,7 @@ Released 2018-09-13 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`skip_while_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#skip_while_next [`slow_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#slow_vector_initialization [`stable_sort_primitive`]: https://rust-lang.github.io/rust-clippy/master/index.html#stable_sort_primitive @@ -2124,7 +2125,6 @@ Released 2018-09-13 [`unreadable_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#unreadable_literal [`unsafe_derive_deserialize`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_derive_deserialize [`unsafe_removed_from_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_removed_from_name -[`unsafe_sizeof_count_copies`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_sizeof_count_copies [`unsafe_vector_initialization`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsafe_vector_initialization [`unseparated_literal_suffix`]: https://rust-lang.github.io/rust-clippy/master/index.html#unseparated_literal_suffix [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1bce0130b40..06961064a4b 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -306,6 +306,7 @@ mod self_assignment; mod serde_api; mod shadow; mod single_component_path_imports; +mod size_of_in_element_count; mod slow_vector_initialization; mod stable_sort_primitive; mod strings; @@ -329,7 +330,6 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; -mod unsafe_sizeof_count_copies; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -917,7 +917,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - &unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES, + &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -1000,7 +1000,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || box matches::Matches::new(msrv)); store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); - store.register_late_pass(|| box unsafe_sizeof_count_copies::UnsafeSizeofCountCopies); + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); store.register_late_pass(|| box map_clone::MapClone); store.register_late_pass(|| box map_err_ignore::MapErrIgnore); store.register_late_pass(|| box shadow::Shadow); @@ -1608,7 +1608,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1887,7 +1887,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&unsafe_sizeof_count_copies::UNSAFE_SIZEOF_COUNT_COPIES), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/unsafe_sizeof_count_copies.rs b/clippy_lints/src/size_of_in_element_count.rs similarity index 63% rename from clippy_lints/src/unsafe_sizeof_count_copies.rs rename to clippy_lints/src/size_of_in_element_count.rs index 8a4538091e7..9701e793700 100644 --- a/clippy_lints/src/unsafe_sizeof_count_copies.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -1,5 +1,5 @@ -//! Lint on unsafe memory copying that use the `size_of` of the pointee type instead of a pointee -//! count +//! Lint on use of `size_of` or `size_of_val` of T in an expression +//! expecting a count of T use crate::utils::{match_def_path, paths, span_lint_and_help}; use if_chain::if_chain; @@ -11,15 +11,11 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// **What it does:** Detects expressions where - /// size_of:: is used as the count argument to unsafe - /// memory copying functions like ptr::copy and - /// ptr::copy_nonoverlapping where T is the pointee type - /// of the pointers used + /// size_of:: or size_of_val:: is used as a + /// count of elements of type T /// /// **Why is this bad?** These functions expect a count - /// of T and not a number of bytes, which can lead to - /// copying the incorrect amount of bytes, which can - /// result in Undefined Behaviour + /// of T and not a number of bytes /// /// **Known problems:** None. /// @@ -33,12 +29,12 @@ declare_clippy_lint! { /// let mut y = [2u8; SIZE]; /// unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; /// ``` - pub UNSAFE_SIZEOF_COUNT_COPIES, + pub SIZE_OF_IN_ELEMENT_COUNT, correctness, - "unsafe memory copying using a byte count instead of a count of T" + "using size_of:: or size_of_val:: where a count of elements of T is expected" } -declare_lint_pass!(UnsafeSizeofCountCopies => [UNSAFE_SIZEOF_COUNT_COPIES]); +declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]); fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option> { match expr.kind { @@ -62,18 +58,30 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { if_chain! { // Find calls to ptr::{copy, copy_nonoverlapping} // and ptr::{swap_nonoverlapping, write_bytes}, if let ExprKind::Call(func, args) = expr.kind; - if let [_, _, count] = args; + if let [.., count] = args; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::COPY_NONOVERLAPPING) - || match_def_path(cx, def_id, &paths::COPY) - || match_def_path(cx, def_id, &paths::WRITE_BYTES) - || match_def_path(cx, def_id, &paths::PTR_SWAP_NONOVERLAPPING); + if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); // Get the pointee type if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); @@ -86,8 +94,7 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; if let [ptr_self, _, count] = args; let method_ident = method_path.ident.as_str(); - if method_ident == "write_bytes" || method_ident == "copy_to" || method_ident == "copy_from" - || method_ident == "copy_to_nonoverlapping" || method_ident == "copy_from_nonoverlapping"; + if METHODS.iter().any(|m| *m == &*method_ident); // Get the pointee type if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = @@ -96,31 +103,16 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - return Some((pointee_ty, count)); } }; - if_chain! { - // Find calls to ptr::copy and copy_nonoverlapping - if let ExprKind::Call(func, args) = expr.kind; - if let [_data, count] = args; - if let ExprKind::Path(ref func_qpath) = func.kind; - if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS) - || match_def_path(cx, def_id, &paths::PTR_SLICE_FROM_RAW_PARTS_MUT); - - // Get the pointee type - if let Some(pointee_ty) = cx.typeck_results().node_substs(func.hir_id).types().next(); - then { - return Some((pointee_ty, count)); - } - }; None } -impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { +impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - const HELP_MSG: &str = "use a count of elements instead of a count of bytes \ - for the count parameter, it already gets multiplied by the size of the pointed to type"; + const HELP_MSG: &str = "use a count of elements instead of a count of bytes\ + , it already gets multiplied by the size of the type"; - const LINT_MSG: &str = "unsafe memory copying using a byte count \ - (multiplied by size_of/size_of_val::) instead of a count of T"; + const LINT_MSG: &str = "found a count of bytes \ + instead of a count of elements of T"; if_chain! { // Find calls to unsafe copy functions and get @@ -134,8 +126,8 @@ impl<'tcx> LateLintPass<'tcx> for UnsafeSizeofCountCopies { then { span_lint_and_help( cx, - UNSAFE_SIZEOF_COUNT_COPIES, - expr.span, + SIZE_OF_IN_ELEMENT_COUNT, + count_expr.span, LINT_MSG, None, HELP_MSG diff --git a/tests/ui/unsafe_sizeof_count_copies.rs b/tests/ui/size_of_in_element_count.rs similarity index 86% rename from tests/ui/unsafe_sizeof_count_copies.rs rename to tests/ui/size_of_in_element_count.rs index 2a9adeb6bd9..d4658ebf72d 100644 --- a/tests/ui/unsafe_sizeof_count_copies.rs +++ b/tests/ui/size_of_in_element_count.rs @@ -1,8 +1,9 @@ -#![warn(clippy::unsafe_sizeof_count_copies)] +#![warn(clippy::size_of_in_element_count)] use std::mem::{size_of, size_of_val}; use std::ptr::{ - copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, + copy, copy_nonoverlapping, slice_from_raw_parts, + slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, }; fn main() { @@ -29,8 +30,8 @@ fn main() { unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; - unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr new file mode 100644 index 00000000000..80c3fec1b05 --- /dev/null +++ b/tests/ui/size_of_in_element_count.stderr @@ -0,0 +1,131 @@ +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:17:68 + | +LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = note: `-D clippy::size-of-in-element-count` implied by `-D warnings` + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:18:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:20:49 + | +LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:21:64 + | +LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:22:51 + | +LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:23:66 + | +LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:25:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:26:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; + | ^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:28:46 + | +LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:29:47 + | +LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:31:66 + | +LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:33:46 + | +LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:34:38 + | +LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:37:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:40:62 + | +LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:43:47 + | +LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: aborting due to 16 previous errors + diff --git a/tests/ui/unsafe_sizeof_count_copies.stderr b/tests/ui/unsafe_sizeof_count_copies.stderr deleted file mode 100644 index 7989e96dd21..00000000000 --- a/tests/ui/unsafe_sizeof_count_copies.stderr +++ /dev/null @@ -1,131 +0,0 @@ -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:16:14 - | -LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::unsafe-sizeof-count-copies` implied by `-D warnings` - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:17:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:19:14 - | -LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:20:14 - | -LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:21:14 - | -LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:22:14 - | -LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:24:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:25:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:27:14 - | -LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:28:14 - | -LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:30:14 - | -LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:32:14 - | -LL | unsafe { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:33:14 - | -LL | unsafe { slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:36:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:39:14 - | -LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: unsafe memory copying using a byte count (multiplied by size_of/size_of_val::) instead of a count of T - --> $DIR/unsafe_sizeof_count_copies.rs:42:14 - | -LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: use a count of elements instead of a count of bytes for the count parameter, it already gets multiplied by the size of the pointed to type - -error: aborting due to 16 previous errors - From c1a5329475d041dbeb077ecda6ae71f690b4bcc1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 30 Nov 2020 21:54:50 -0300 Subject: [PATCH 6/6] Add more functions to size_of_in_element_count Specifically ptr::{sub, wrapping_sub, add, wrapping_add, offset, wrapping_offset} and slice::{from_raw_parts, from_raw_parts_mut} The lint now also looks for size_of calls through casts (Since offset takes an isize) --- clippy_lints/src/lib.rs | 6 +- clippy_lints/src/size_of_in_element_count.rs | 50 +++++----- clippy_lints/src/utils/paths.rs | 2 + tests/ui/size_of_in_element_count.rs | 15 ++- tests/ui/size_of_in_element_count.stderr | 98 ++++++++++++++++---- 5 files changed, 128 insertions(+), 43 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 06961064a4b..4ef595bcffd 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -848,6 +848,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &shadow::SHADOW_SAME, &shadow::SHADOW_UNRELATED, &single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS, + &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &slow_vector_initialization::SLOW_VECTOR_INITIALIZATION, &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, @@ -917,7 +918,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, - &size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT, &unused_io_amount::UNUSED_IO_AMOUNT, &unused_self::UNUSED_SELF, &unused_unit::UNUSED_UNIT, @@ -1562,6 +1562,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), @@ -1608,7 +1609,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), LintId::of(&unwrap::PANICKING_UNWRAP), @@ -1872,6 +1872,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(®ex::INVALID_REGEX), LintId::of(&self_assignment::SELF_ASSIGNMENT), LintId::of(&serde_api::SERDE_API_MISUSE), + LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1887,7 +1888,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unit_return_expecting_ord::UNIT_RETURN_EXPECTING_ORD), LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), - LintId::of(&size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unwrap::PANICKING_UNWRAP), LintId::of(&vec_resize_to_zero::VEC_RESIZE_TO_ZERO), diff --git a/clippy_lints/src/size_of_in_element_count.rs b/clippy_lints/src/size_of_in_element_count.rs index 9701e793700..210cf5773e1 100644 --- a/clippy_lints/src/size_of_in_element_count.rs +++ b/clippy_lints/src/size_of_in_element_count.rs @@ -54,31 +54,40 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { get_size_of_ty(cx, left).or_else(|| get_size_of_ty(cx, right)) }, + ExprKind::Cast(expr, _) => get_size_of_ty(cx, expr), _ => None, } } -const FUNCTIONS: [[&str; 3]; 6] = [ - paths::COPY_NONOVERLAPPING, - paths::COPY, - paths::WRITE_BYTES, - paths::PTR_SWAP_NONOVERLAPPING, - paths::PTR_SLICE_FROM_RAW_PARTS, - paths::PTR_SLICE_FROM_RAW_PARTS_MUT, - ]; -const METHODS: [&str; 5] = [ - "write_bytes", - "copy_to", - "copy_from", - "copy_to_nonoverlapping", - "copy_from_nonoverlapping", - ]; fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> { + const FUNCTIONS: [&[&str]; 8] = [ + &paths::COPY_NONOVERLAPPING, + &paths::COPY, + &paths::WRITE_BYTES, + &paths::PTR_SWAP_NONOVERLAPPING, + &paths::PTR_SLICE_FROM_RAW_PARTS, + &paths::PTR_SLICE_FROM_RAW_PARTS_MUT, + &paths::SLICE_FROM_RAW_PARTS, + &paths::SLICE_FROM_RAW_PARTS_MUT, + ]; + const METHODS: [&str; 11] = [ + "write_bytes", + "copy_to", + "copy_from", + "copy_to_nonoverlapping", + "copy_from_nonoverlapping", + "add", + "wrapping_add", + "sub", + "wrapping_sub", + "offset", + "wrapping_offset", + ]; + if_chain! { // Find calls to ptr::{copy, copy_nonoverlapping} // and ptr::{swap_nonoverlapping, write_bytes}, - if let ExprKind::Call(func, args) = expr.kind; - if let [.., count] = args; + if let ExprKind::Call(func, [.., count]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path)); @@ -91,13 +100,12 @@ fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) - }; if_chain! { // Find calls to copy_{from,to}{,_nonoverlapping} and write_bytes methods - if let ExprKind::MethodCall(method_path, _, args, _) = expr.kind; - if let [ptr_self, _, count] = args; + if let ExprKind::MethodCall(method_path, _, [ptr_self, .., count], _) = expr.kind; let method_ident = method_path.ident.as_str(); if METHODS.iter().any(|m| *m == &*method_ident); // Get the pointee type - if let ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl:_mutability }) = + if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) = cx.typeck_results().expr_ty(ptr_self).kind(); then { return Some((pointee_ty, count)); @@ -115,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for SizeOfInElementCount { instead of a count of elements of T"; if_chain! { - // Find calls to unsafe copy functions and get + // Find calls to functions with an element count parameter and get // the pointee type and count parameter expression if let Some((pointee_ty, count_expr)) = get_pointee_ty_and_count_expr(cx, expr); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 87c020a99db..6fdc7b4587f 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -128,6 +128,8 @@ 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; 3] = ["serde", "de", "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_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"]; pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "", "into_vec"]; pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"]; pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"]; diff --git a/tests/ui/size_of_in_element_count.rs b/tests/ui/size_of_in_element_count.rs index d4658ebf72d..b13e390705a 100644 --- a/tests/ui/size_of_in_element_count.rs +++ b/tests/ui/size_of_in_element_count.rs @@ -1,10 +1,11 @@ #![warn(clippy::size_of_in_element_count)] +#![allow(clippy::ptr_offset_with_cast)] use std::mem::{size_of, size_of_val}; use std::ptr::{ - copy, copy_nonoverlapping, slice_from_raw_parts, - slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, + copy, copy_nonoverlapping, slice_from_raw_parts, slice_from_raw_parts_mut, swap_nonoverlapping, write_bytes, }; +use std::slice::{from_raw_parts, from_raw_parts_mut}; fn main() { const SIZE: usize = 128; @@ -33,6 +34,16 @@ fn main() { slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); + unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + + unsafe { y.as_mut_ptr().sub(size_of::()) }; + y.as_ptr().wrapping_sub(size_of::()); + unsafe { y.as_ptr().add(size_of::()) }; + y.as_mut_ptr().wrapping_add(size_of::()); + unsafe { y.as_ptr().offset(size_of::() as isize) }; + y.as_mut_ptr().wrapping_offset(size_of::() as isize); + // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; diff --git a/tests/ui/size_of_in_element_count.stderr b/tests/ui/size_of_in_element_count.stderr index 80c3fec1b05..b7f421ec997 100644 --- a/tests/ui/size_of_in_element_count.stderr +++ b/tests/ui/size_of_in_element_count.stderr @@ -1,5 +1,5 @@ error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:17:68 + --> $DIR/size_of_in_element_count.rs:18:68 | LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of: = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:18:62 + --> $DIR/size_of_in_element_count.rs:19:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:20:49 + --> $DIR/size_of_in_element_count.rs:21:49 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:21:64 + --> $DIR/size_of_in_element_count.rs:22:64 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of:: $DIR/size_of_in_element_count.rs:22:51 + --> $DIR/size_of_in_element_count.rs:23:51 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:23:66 + --> $DIR/size_of_in_element_count.rs:24:66 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:25:47 + --> $DIR/size_of_in_element_count.rs:26:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:26:47 + --> $DIR/size_of_in_element_count.rs:27:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:28:46 + --> $DIR/size_of_in_element_count.rs:29:46 | LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | unsafe { y.as_mut_ptr().write_bytes(0u8, size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:29:47 + --> $DIR/size_of_in_element_count.rs:30:47 | LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | unsafe { write_bytes(y.as_mut_ptr(), 0u8, size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:31:66 + --> $DIR/size_of_in_element_count.rs:32:66 | LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:33:46 + --> $DIR/size_of_in_element_count.rs:34:46 | LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:34:38 + --> $DIR/size_of_in_element_count.rs:35:38 | LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,71 @@ LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:37:62 + --> $DIR/size_of_in_element_count.rs:37:49 + | +LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:38:41 + | +LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:40:33 + | +LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:41:29 + | +LL | y.as_ptr().wrapping_sub(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:42:29 + | +LL | unsafe { y.as_ptr().add(size_of::()) }; + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:43:33 + | +LL | y.as_mut_ptr().wrapping_add(size_of::()); + | ^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:44:32 + | +LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:45:36 + | +LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type + +error: found a count of bytes instead of a count of elements of T + --> $DIR/size_of_in_element_count.rs:48:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +176,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::( = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:40:62 + --> $DIR/size_of_in_element_count.rs:51:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,12 +184,12 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * si = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of T - --> $DIR/size_of_in_element_count.rs:43:47 + --> $DIR/size_of_in_element_count.rs:54:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type -error: aborting due to 16 previous errors +error: aborting due to 24 previous errors