mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 09:44:08 +00:00
Move TransmutingNull
into Transmute
lint pass
This commit is contained in:
parent
e834855950
commit
e213b6ee35
@ -315,10 +315,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
|||||||
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
|
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
|
||||||
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
|
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
|
||||||
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
|
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
|
||||||
|
LintId::of(transmute::TRANSMUTING_NULL),
|
||||||
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
||||||
LintId::of(transmute::USELESS_TRANSMUTE),
|
LintId::of(transmute::USELESS_TRANSMUTE),
|
||||||
LintId::of(transmute::WRONG_TRANSMUTE),
|
LintId::of(transmute::WRONG_TRANSMUTE),
|
||||||
LintId::of(transmuting_null::TRANSMUTING_NULL),
|
|
||||||
LintId::of(types::BORROWED_BOX),
|
LintId::of(types::BORROWED_BOX),
|
||||||
LintId::of(types::BOX_COLLECTION),
|
LintId::of(types::BOX_COLLECTION),
|
||||||
LintId::of(types::REDUNDANT_ALLOCATION),
|
LintId::of(types::REDUNDANT_ALLOCATION),
|
||||||
|
@ -62,9 +62,9 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
|
|||||||
LintId::of(serde_api::SERDE_API_MISUSE),
|
LintId::of(serde_api::SERDE_API_MISUSE),
|
||||||
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
|
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
|
||||||
LintId::of(swap::ALMOST_SWAPPED),
|
LintId::of(swap::ALMOST_SWAPPED),
|
||||||
|
LintId::of(transmute::TRANSMUTING_NULL),
|
||||||
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
|
||||||
LintId::of(transmute::WRONG_TRANSMUTE),
|
LintId::of(transmute::WRONG_TRANSMUTE),
|
||||||
LintId::of(transmuting_null::TRANSMUTING_NULL),
|
|
||||||
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
LintId::of(unicode::INVISIBLE_CHARACTERS),
|
||||||
LintId::of(uninit_vec::UNINIT_VEC),
|
LintId::of(uninit_vec::UNINIT_VEC),
|
||||||
LintId::of(unit_hash::UNIT_HASH),
|
LintId::of(unit_hash::UNIT_HASH),
|
||||||
|
@ -540,10 +540,10 @@ store.register_lints(&[
|
|||||||
transmute::TRANSMUTE_PTR_TO_PTR,
|
transmute::TRANSMUTE_PTR_TO_PTR,
|
||||||
transmute::TRANSMUTE_PTR_TO_REF,
|
transmute::TRANSMUTE_PTR_TO_REF,
|
||||||
transmute::TRANSMUTE_UNDEFINED_REPR,
|
transmute::TRANSMUTE_UNDEFINED_REPR,
|
||||||
|
transmute::TRANSMUTING_NULL,
|
||||||
transmute::UNSOUND_COLLECTION_TRANSMUTE,
|
transmute::UNSOUND_COLLECTION_TRANSMUTE,
|
||||||
transmute::USELESS_TRANSMUTE,
|
transmute::USELESS_TRANSMUTE,
|
||||||
transmute::WRONG_TRANSMUTE,
|
transmute::WRONG_TRANSMUTE,
|
||||||
transmuting_null::TRANSMUTING_NULL,
|
|
||||||
types::BORROWED_BOX,
|
types::BORROWED_BOX,
|
||||||
types::BOX_COLLECTION,
|
types::BOX_COLLECTION,
|
||||||
types::LINKEDLIST,
|
types::LINKEDLIST,
|
||||||
|
@ -367,7 +367,6 @@ mod to_digit_is_some;
|
|||||||
mod trailing_empty_array;
|
mod trailing_empty_array;
|
||||||
mod trait_bounds;
|
mod trait_bounds;
|
||||||
mod transmute;
|
mod transmute;
|
||||||
mod transmuting_null;
|
|
||||||
mod types;
|
mod types;
|
||||||
mod undocumented_unsafe_blocks;
|
mod undocumented_unsafe_blocks;
|
||||||
mod unicode;
|
mod unicode;
|
||||||
@ -723,7 +722,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
|
|||||||
store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
|
store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
|
||||||
store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
|
store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
|
||||||
store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
|
store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
|
||||||
store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
|
|
||||||
store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
|
store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
|
||||||
let max_trait_bounds = conf.max_trait_bounds;
|
let max_trait_bounds = conf.max_trait_bounds;
|
||||||
store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
|
store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
|
||||||
|
@ -9,6 +9,7 @@ mod transmute_ptr_to_ref;
|
|||||||
mod transmute_ref_to_ref;
|
mod transmute_ref_to_ref;
|
||||||
mod transmute_undefined_repr;
|
mod transmute_undefined_repr;
|
||||||
mod transmutes_expressible_as_ptr_casts;
|
mod transmutes_expressible_as_ptr_casts;
|
||||||
|
mod transmuting_null;
|
||||||
mod unsound_collection_transmute;
|
mod unsound_collection_transmute;
|
||||||
mod useless_transmute;
|
mod useless_transmute;
|
||||||
mod utils;
|
mod utils;
|
||||||
@ -386,6 +387,28 @@ declare_clippy_lint! {
|
|||||||
"transmute to or from a type with an undefined representation"
|
"transmute to or from a type with an undefined representation"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for transmute calls which would receive a null pointer.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Transmuting a null pointer is undefined behavior.
|
||||||
|
///
|
||||||
|
/// ### Known problems
|
||||||
|
/// Not all cases can be detected at the moment of this writing.
|
||||||
|
/// For example, variables which hold a null pointer and are then fed to a `transmute`
|
||||||
|
/// call, aren't detectable yet.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```rust
|
||||||
|
/// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.35.0"]
|
||||||
|
pub TRANSMUTING_NULL,
|
||||||
|
correctness,
|
||||||
|
"transmutes from a null pointer to a reference, which is undefined behavior"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Transmute {
|
pub struct Transmute {
|
||||||
msrv: Option<RustcVersion>,
|
msrv: Option<RustcVersion>,
|
||||||
}
|
}
|
||||||
@ -404,6 +427,7 @@ impl_lint_pass!(Transmute => [
|
|||||||
UNSOUND_COLLECTION_TRANSMUTE,
|
UNSOUND_COLLECTION_TRANSMUTE,
|
||||||
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
|
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
|
||||||
TRANSMUTE_UNDEFINED_REPR,
|
TRANSMUTE_UNDEFINED_REPR,
|
||||||
|
TRANSMUTING_NULL,
|
||||||
]);
|
]);
|
||||||
impl Transmute {
|
impl Transmute {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
@ -436,6 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
|
|||||||
|
|
||||||
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
|
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
|
||||||
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
|
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
|
||||||
|
| transmuting_null::check(cx, e, arg, to_ty)
|
||||||
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
|
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
|
||||||
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
|
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
|
||||||
|
61
clippy_lints/src/transmute/transmuting_null.rs
Normal file
61
clippy_lints/src/transmute/transmuting_null.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use clippy_utils::consts::{constant_context, Constant};
|
||||||
|
use clippy_utils::diagnostics::span_lint;
|
||||||
|
use clippy_utils::is_expr_diagnostic_item;
|
||||||
|
use if_chain::if_chain;
|
||||||
|
use rustc_ast::LitKind;
|
||||||
|
use rustc_hir::{Expr, ExprKind};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_middle::ty::Ty;
|
||||||
|
use rustc_span::symbol::sym;
|
||||||
|
|
||||||
|
use super::TRANSMUTING_NULL;
|
||||||
|
|
||||||
|
const LINT_MSG: &str = "transmuting a known null pointer into a reference";
|
||||||
|
|
||||||
|
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
|
||||||
|
if !to_ty.is_ref() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catching transmute over constants that resolve to `null`.
|
||||||
|
let mut const_eval_context = constant_context(cx, cx.typeck_results());
|
||||||
|
if_chain! {
|
||||||
|
if let ExprKind::Path(ref _qpath) = arg.kind;
|
||||||
|
if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
|
||||||
|
if x == 0;
|
||||||
|
then {
|
||||||
|
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catching:
|
||||||
|
// `std::mem::transmute(0 as *const i32)`
|
||||||
|
if_chain! {
|
||||||
|
if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
|
||||||
|
if let ExprKind::Lit(ref lit) = inner_expr.kind;
|
||||||
|
if let LitKind::Int(0, _) = lit.node;
|
||||||
|
then {
|
||||||
|
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Catching:
|
||||||
|
// `std::mem::transmute(std::ptr::null::<i32>())`
|
||||||
|
if_chain! {
|
||||||
|
if let ExprKind::Call(func1, []) = arg.kind;
|
||||||
|
if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
|
||||||
|
then {
|
||||||
|
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME:
|
||||||
|
// Also catch transmutations of variables which are known nulls.
|
||||||
|
// To do this, MIR const propagation seems to be the better tool.
|
||||||
|
// Whenever MIR const prop routines are more developed, this will
|
||||||
|
// become available. As of this writing (25/03/19) it is not yet.
|
||||||
|
false
|
||||||
|
}
|
@ -1,89 +0,0 @@
|
|||||||
use clippy_utils::consts::{constant_context, Constant};
|
|
||||||
use clippy_utils::diagnostics::span_lint;
|
|
||||||
use clippy_utils::is_expr_diagnostic_item;
|
|
||||||
use if_chain::if_chain;
|
|
||||||
use rustc_ast::LitKind;
|
|
||||||
use rustc_hir::{Expr, ExprKind};
|
|
||||||
use rustc_lint::{LateContext, LateLintPass, LintContext};
|
|
||||||
use rustc_middle::lint::in_external_macro;
|
|
||||||
use rustc_session::{declare_lint_pass, declare_tool_lint};
|
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
|
||||||
/// ### What it does
|
|
||||||
/// Checks for transmute calls which would receive a null pointer.
|
|
||||||
///
|
|
||||||
/// ### Why is this bad?
|
|
||||||
/// Transmuting a null pointer is undefined behavior.
|
|
||||||
///
|
|
||||||
/// ### Known problems
|
|
||||||
/// Not all cases can be detected at the moment of this writing.
|
|
||||||
/// For example, variables which hold a null pointer and are then fed to a `transmute`
|
|
||||||
/// call, aren't detectable yet.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
/// ```rust
|
|
||||||
/// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
|
|
||||||
/// ```
|
|
||||||
#[clippy::version = "1.35.0"]
|
|
||||||
pub TRANSMUTING_NULL,
|
|
||||||
correctness,
|
|
||||||
"transmutes from a null pointer to a reference, which is undefined behavior"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_lint_pass!(TransmutingNull => [TRANSMUTING_NULL]);
|
|
||||||
|
|
||||||
const LINT_MSG: &str = "transmuting a known null pointer into a reference";
|
|
||||||
|
|
||||||
impl<'tcx> LateLintPass<'tcx> for TransmutingNull {
|
|
||||||
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|
||||||
if in_external_macro(cx.sess(), expr.span) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if_chain! {
|
|
||||||
if let ExprKind::Call(func, [arg]) = expr.kind;
|
|
||||||
if is_expr_diagnostic_item(cx, func, sym::transmute);
|
|
||||||
|
|
||||||
then {
|
|
||||||
// Catching transmute over constants that resolve to `null`.
|
|
||||||
let mut const_eval_context = constant_context(cx, cx.typeck_results());
|
|
||||||
if_chain! {
|
|
||||||
if let ExprKind::Path(ref _qpath) = arg.kind;
|
|
||||||
if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
|
|
||||||
if x == 0;
|
|
||||||
then {
|
|
||||||
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Catching:
|
|
||||||
// `std::mem::transmute(0 as *const i32)`
|
|
||||||
if_chain! {
|
|
||||||
if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
|
|
||||||
if let ExprKind::Lit(ref lit) = inner_expr.kind;
|
|
||||||
if let LitKind::Int(0, _) = lit.node;
|
|
||||||
then {
|
|
||||||
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Catching:
|
|
||||||
// `std::mem::transmute(std::ptr::null::<i32>())`
|
|
||||||
if_chain! {
|
|
||||||
if let ExprKind::Call(func1, []) = arg.kind;
|
|
||||||
if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
|
|
||||||
then {
|
|
||||||
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME:
|
|
||||||
// Also catch transmutations of variables which are known nulls.
|
|
||||||
// To do this, MIR const propagation seems to be the better tool.
|
|
||||||
// Whenever MIR const prop routines are more developed, this will
|
|
||||||
// become available. As of this writing (25/03/19) it is not yet.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user