Auto merge of #9247 - clubby789:raw_slice_pointer_cast, r=Alexendoo
New lint: Raw slice pointer cast Adds a lint to check for a raw slice being created and cast back to a pointer, suggesting `ptr::slice_from_raw_parts`, to identify UB such as https://github.com/SimonSapin/rust-typed-arena/pull/54. ``` changelog: [`cast_slice_from_raw_parts`]: Add lint to check for `slice::from_raw_parts(.., ..) as *const _` ```
This commit is contained in:
commit
e9f7ce1f91
@ -3627,6 +3627,7 @@ Released 2018-09-13
|
|||||||
[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
|
[`cast_ref_to_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_ref_to_mut
|
||||||
[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
|
[`cast_sign_loss`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_sign_loss
|
||||||
[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
|
[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
|
||||||
|
[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
|
||||||
[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
|
[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
|
||||||
[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
|
[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
|
||||||
[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
|
[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
|
||||||
|
63
clippy_lints/src/casts/cast_slice_from_raw_parts.rs
Normal file
63
clippy_lints/src/casts/cast_slice_from_raw_parts.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
|
use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{def_id::DefId, Expr, ExprKind};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty::{self, Ty};
|
||||||
|
use rustc_semver::RustcVersion;
|
||||||
|
|
||||||
|
use super::CAST_SLICE_FROM_RAW_PARTS;
|
||||||
|
|
||||||
|
enum RawPartsKind {
|
||||||
|
Immutable,
|
||||||
|
Mutable,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
|
||||||
|
if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
|
||||||
|
Some(RawPartsKind::Immutable)
|
||||||
|
} else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
|
||||||
|
Some(RawPartsKind::Mutable)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn check(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
expr: &Expr<'_>,
|
||||||
|
cast_expr: &Expr<'_>,
|
||||||
|
cast_to: Ty<'_>,
|
||||||
|
msrv: Option<RustcVersion>,
|
||||||
|
) {
|
||||||
|
if_chain! {
|
||||||
|
if meets_msrv(msrv, msrvs::PTR_SLICE_RAW_PARTS);
|
||||||
|
if let ty::RawPtr(ptrty) = cast_to.kind();
|
||||||
|
if let ty::Slice(_) = ptrty.ty.kind();
|
||||||
|
if let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind;
|
||||||
|
if let ExprKind::Path(ref qpath) = fun.kind;
|
||||||
|
if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
|
||||||
|
if let Some(rpk) = raw_parts_kind(cx, fun_def_id);
|
||||||
|
then {
|
||||||
|
let func = match rpk {
|
||||||
|
RawPartsKind::Immutable => "from_raw_parts",
|
||||||
|
RawPartsKind::Mutable => "from_raw_parts_mut"
|
||||||
|
};
|
||||||
|
let span = expr.span;
|
||||||
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
let ptr = snippet_with_applicability(cx, ptr_arg.span, "ptr", &mut applicability);
|
||||||
|
let len = snippet_with_applicability(cx, len_arg.span, "len", &mut applicability);
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
CAST_SLICE_FROM_RAW_PARTS,
|
||||||
|
span,
|
||||||
|
&format!("casting the result of `{func}` to {cast_to}"),
|
||||||
|
"replace with",
|
||||||
|
format!("core::ptr::slice_{func}({ptr}, {len})"),
|
||||||
|
applicability
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ mod cast_ptr_alignment;
|
|||||||
mod cast_ref_to_mut;
|
mod cast_ref_to_mut;
|
||||||
mod cast_sign_loss;
|
mod cast_sign_loss;
|
||||||
mod cast_slice_different_sizes;
|
mod cast_slice_different_sizes;
|
||||||
|
mod cast_slice_from_raw_parts;
|
||||||
mod char_lit_as_u8;
|
mod char_lit_as_u8;
|
||||||
mod fn_to_numeric_cast;
|
mod fn_to_numeric_cast;
|
||||||
mod fn_to_numeric_cast_any;
|
mod fn_to_numeric_cast_any;
|
||||||
@ -568,6 +569,32 @@ declare_clippy_lint! {
|
|||||||
pedantic,
|
pedantic,
|
||||||
"borrowing just to cast to a raw pointer"
|
"borrowing just to cast to a raw pointer"
|
||||||
}
|
}
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for a raw slice being cast to a slice pointer
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// This can result in multiple `&mut` references to the same location when only a pointer is
|
||||||
|
/// required.
|
||||||
|
/// `ptr::slice_from_raw_parts` is a safe alternative that doesn't require
|
||||||
|
/// the same [safety requirements] to be upheld.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let _: *const [u8] = std::slice::from_raw_parts(ptr, len) as *const _;
|
||||||
|
/// let _: *mut [u8] = std::slice::from_raw_parts_mut(ptr, len) as *mut _;
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// let _: *const [u8] = std::ptr::slice_from_raw_parts(ptr, len);
|
||||||
|
/// let _: *mut [u8] = std::ptr::slice_from_raw_parts_mut(ptr, len);
|
||||||
|
/// ```
|
||||||
|
/// [safety requirements]: https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html#safety
|
||||||
|
#[clippy::version = "1.64.0"]
|
||||||
|
pub CAST_SLICE_FROM_RAW_PARTS,
|
||||||
|
suspicious,
|
||||||
|
"casting a slice created from a pointer and length to a slice pointer"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Casts {
|
pub struct Casts {
|
||||||
msrv: Option<RustcVersion>,
|
msrv: Option<RustcVersion>,
|
||||||
@ -600,6 +627,7 @@ impl_lint_pass!(Casts => [
|
|||||||
CAST_ABS_TO_UNSIGNED,
|
CAST_ABS_TO_UNSIGNED,
|
||||||
AS_UNDERSCORE,
|
AS_UNDERSCORE,
|
||||||
BORROW_AS_PTR,
|
BORROW_AS_PTR,
|
||||||
|
CAST_SLICE_FROM_RAW_PARTS
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for Casts {
|
impl<'tcx> LateLintPass<'tcx> for Casts {
|
||||||
@ -624,7 +652,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
|
|||||||
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
|
if unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, self.msrv);
|
||||||
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
|
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||||
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
|
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||||
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
|
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to);
|
||||||
|
@ -25,6 +25,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||||||
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
||||||
LintId::of(casts::CAST_REF_TO_MUT),
|
LintId::of(casts::CAST_REF_TO_MUT),
|
||||||
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
|
LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
|
||||||
|
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
|
||||||
LintId::of(casts::CHAR_LIT_AS_U8),
|
LintId::of(casts::CHAR_LIT_AS_U8),
|
||||||
LintId::of(casts::FN_TO_NUMERIC_CAST),
|
LintId::of(casts::FN_TO_NUMERIC_CAST),
|
||||||
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
LintId::of(casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION),
|
||||||
|
@ -77,6 +77,7 @@ store.register_lints(&[
|
|||||||
casts::CAST_REF_TO_MUT,
|
casts::CAST_REF_TO_MUT,
|
||||||
casts::CAST_SIGN_LOSS,
|
casts::CAST_SIGN_LOSS,
|
||||||
casts::CAST_SLICE_DIFFERENT_SIZES,
|
casts::CAST_SLICE_DIFFERENT_SIZES,
|
||||||
|
casts::CAST_SLICE_FROM_RAW_PARTS,
|
||||||
casts::CHAR_LIT_AS_U8,
|
casts::CHAR_LIT_AS_U8,
|
||||||
casts::FN_TO_NUMERIC_CAST,
|
casts::FN_TO_NUMERIC_CAST,
|
||||||
casts::FN_TO_NUMERIC_CAST_ANY,
|
casts::FN_TO_NUMERIC_CAST_ANY,
|
||||||
|
@ -11,6 +11,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
|
|||||||
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
|
LintId::of(casts::CAST_ABS_TO_UNSIGNED),
|
||||||
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
|
LintId::of(casts::CAST_ENUM_CONSTRUCTOR),
|
||||||
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
LintId::of(casts::CAST_ENUM_TRUNCATION),
|
||||||
|
LintId::of(casts::CAST_SLICE_FROM_RAW_PARTS),
|
||||||
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
|
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
|
||||||
LintId::of(drop_forget_ref::DROP_NON_DROP),
|
LintId::of(drop_forget_ref::DROP_NON_DROP),
|
||||||
LintId::of(drop_forget_ref::FORGET_NON_DROP),
|
LintId::of(drop_forget_ref::FORGET_NON_DROP),
|
||||||
|
24
tests/ui/cast_raw_slice_pointer_cast.fixed
Normal file
24
tests/ui/cast_raw_slice_pointer_cast.fixed
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::cast_slice_from_raw_parts)]
|
||||||
|
|
||||||
|
#[allow(unused_imports, unused_unsafe)]
|
||||||
|
fn main() {
|
||||||
|
let mut vec = vec![0u8; 1];
|
||||||
|
let ptr: *const u8 = vec.as_ptr();
|
||||||
|
let mptr = vec.as_mut_ptr();
|
||||||
|
let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
|
||||||
|
let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
|
||||||
|
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
|
||||||
|
{
|
||||||
|
use core::slice;
|
||||||
|
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
|
||||||
|
use slice as one;
|
||||||
|
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
use std::slice;
|
||||||
|
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
|
||||||
|
use slice as one;
|
||||||
|
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
|
||||||
|
}
|
||||||
|
}
|
24
tests/ui/cast_raw_slice_pointer_cast.rs
Normal file
24
tests/ui/cast_raw_slice_pointer_cast.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// run-rustfix
|
||||||
|
#![warn(clippy::cast_slice_from_raw_parts)]
|
||||||
|
|
||||||
|
#[allow(unused_imports, unused_unsafe)]
|
||||||
|
fn main() {
|
||||||
|
let mut vec = vec![0u8; 1];
|
||||||
|
let ptr: *const u8 = vec.as_ptr();
|
||||||
|
let mptr = vec.as_mut_ptr();
|
||||||
|
let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
|
||||||
|
let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
|
||||||
|
let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
{
|
||||||
|
use core::slice;
|
||||||
|
let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
use slice as one;
|
||||||
|
let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
use std::slice;
|
||||||
|
let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
use slice as one;
|
||||||
|
let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
}
|
||||||
|
}
|
46
tests/ui/cast_raw_slice_pointer_cast.stderr
Normal file
46
tests/ui/cast_raw_slice_pointer_cast.stderr
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:9:35
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::cast-slice-from-raw-parts` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts_mut` to *mut [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:10:35
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:11:26
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:14:30
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:16:30
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:20:30
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
||||||
|
error: casting the result of `from_raw_parts` to *const [u8]
|
||||||
|
--> $DIR/cast_raw_slice_pointer_cast.rs:22:30
|
||||||
|
|
|
||||||
|
LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user