Skip to content

Commit e213b6e

Browse files
committed
Move TransmutingNull into Transmute lint pass
1 parent e834855 commit e213b6e

File tree

7 files changed

+89
-94
lines changed

7 files changed

+89
-94
lines changed

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
315315
LintId::of(transmute::TRANSMUTE_INT_TO_FLOAT),
316316
LintId::of(transmute::TRANSMUTE_NUM_TO_BYTES),
317317
LintId::of(transmute::TRANSMUTE_PTR_TO_REF),
318+
LintId::of(transmute::TRANSMUTING_NULL),
318319
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
319320
LintId::of(transmute::USELESS_TRANSMUTE),
320321
LintId::of(transmute::WRONG_TRANSMUTE),
321-
LintId::of(transmuting_null::TRANSMUTING_NULL),
322322
LintId::of(types::BORROWED_BOX),
323323
LintId::of(types::BOX_COLLECTION),
324324
LintId::of(types::REDUNDANT_ALLOCATION),

clippy_lints/src/lib.register_correctness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
6262
LintId::of(serde_api::SERDE_API_MISUSE),
6363
LintId::of(size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT),
6464
LintId::of(swap::ALMOST_SWAPPED),
65+
LintId::of(transmute::TRANSMUTING_NULL),
6566
LintId::of(transmute::UNSOUND_COLLECTION_TRANSMUTE),
6667
LintId::of(transmute::WRONG_TRANSMUTE),
67-
LintId::of(transmuting_null::TRANSMUTING_NULL),
6868
LintId::of(unicode::INVISIBLE_CHARACTERS),
6969
LintId::of(uninit_vec::UNINIT_VEC),
7070
LintId::of(unit_hash::UNIT_HASH),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,10 +540,10 @@ store.register_lints(&[
540540
transmute::TRANSMUTE_PTR_TO_PTR,
541541
transmute::TRANSMUTE_PTR_TO_REF,
542542
transmute::TRANSMUTE_UNDEFINED_REPR,
543+
transmute::TRANSMUTING_NULL,
543544
transmute::UNSOUND_COLLECTION_TRANSMUTE,
544545
transmute::USELESS_TRANSMUTE,
545546
transmute::WRONG_TRANSMUTE,
546-
transmuting_null::TRANSMUTING_NULL,
547547
types::BORROWED_BOX,
548548
types::BOX_COLLECTION,
549549
types::LINKEDLIST,

clippy_lints/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,6 @@ mod to_digit_is_some;
367367
mod trailing_empty_array;
368368
mod trait_bounds;
369369
mod transmute;
370-
mod transmuting_null;
371370
mod types;
372371
mod undocumented_unsafe_blocks;
373372
mod unicode;
@@ -723,7 +722,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
723722
store.register_late_pass(move || Box::new(unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)));
724723
store.register_late_pass(|| Box::new(assertions_on_constants::AssertionsOnConstants));
725724
store.register_late_pass(|| Box::new(assertions_on_result_states::AssertionsOnResultStates));
726-
store.register_late_pass(|| Box::new(transmuting_null::TransmutingNull));
727725
store.register_late_pass(|| Box::new(inherent_to_string::InherentToString));
728726
let max_trait_bounds = conf.max_trait_bounds;
729727
store.register_late_pass(move || Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));

clippy_lints/src/transmute/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ mod transmute_ptr_to_ref;
99
mod transmute_ref_to_ref;
1010
mod transmute_undefined_repr;
1111
mod transmutes_expressible_as_ptr_casts;
12+
mod transmuting_null;
1213
mod unsound_collection_transmute;
1314
mod useless_transmute;
1415
mod utils;
@@ -386,6 +387,28 @@ declare_clippy_lint! {
386387
"transmute to or from a type with an undefined representation"
387388
}
388389

390+
declare_clippy_lint! {
391+
/// ### What it does
392+
/// Checks for transmute calls which would receive a null pointer.
393+
///
394+
/// ### Why is this bad?
395+
/// Transmuting a null pointer is undefined behavior.
396+
///
397+
/// ### Known problems
398+
/// Not all cases can be detected at the moment of this writing.
399+
/// For example, variables which hold a null pointer and are then fed to a `transmute`
400+
/// call, aren't detectable yet.
401+
///
402+
/// ### Example
403+
/// ```rust
404+
/// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
405+
/// ```
406+
#[clippy::version = "1.35.0"]
407+
pub TRANSMUTING_NULL,
408+
correctness,
409+
"transmutes from a null pointer to a reference, which is undefined behavior"
410+
}
411+
389412
pub struct Transmute {
390413
msrv: Option<RustcVersion>,
391414
}
@@ -404,6 +427,7 @@ impl_lint_pass!(Transmute => [
404427
UNSOUND_COLLECTION_TRANSMUTE,
405428
TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
406429
TRANSMUTE_UNDEFINED_REPR,
430+
TRANSMUTING_NULL,
407431
]);
408432
impl Transmute {
409433
#[must_use]
@@ -436,6 +460,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute {
436460

437461
let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
438462
| crosspointer_transmute::check(cx, e, from_ty, to_ty)
463+
| transmuting_null::check(cx, e, arg, to_ty)
439464
| transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, path, self.msrv)
440465
| transmute_int_to_char::check(cx, e, from_ty, to_ty, arg, const_context)
441466
| transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use clippy_utils::consts::{constant_context, Constant};
2+
use clippy_utils::diagnostics::span_lint;
3+
use clippy_utils::is_expr_diagnostic_item;
4+
use if_chain::if_chain;
5+
use rustc_ast::LitKind;
6+
use rustc_hir::{Expr, ExprKind};
7+
use rustc_lint::LateContext;
8+
use rustc_middle::ty::Ty;
9+
use rustc_span::symbol::sym;
10+
11+
use super::TRANSMUTING_NULL;
12+
13+
const LINT_MSG: &str = "transmuting a known null pointer into a reference";
14+
15+
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'tcx Expr<'_>, to_ty: Ty<'tcx>) -> bool {
16+
if !to_ty.is_ref() {
17+
return false;
18+
}
19+
20+
// Catching transmute over constants that resolve to `null`.
21+
let mut const_eval_context = constant_context(cx, cx.typeck_results());
22+
if_chain! {
23+
if let ExprKind::Path(ref _qpath) = arg.kind;
24+
if let Some(Constant::RawPtr(x)) = const_eval_context.expr(arg);
25+
if x == 0;
26+
then {
27+
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
28+
return true;
29+
}
30+
}
31+
32+
// Catching:
33+
// `std::mem::transmute(0 as *const i32)`
34+
if_chain! {
35+
if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind;
36+
if let ExprKind::Lit(ref lit) = inner_expr.kind;
37+
if let LitKind::Int(0, _) = lit.node;
38+
then {
39+
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
40+
return true;
41+
}
42+
}
43+
44+
// Catching:
45+
// `std::mem::transmute(std::ptr::null::<i32>())`
46+
if_chain! {
47+
if let ExprKind::Call(func1, []) = arg.kind;
48+
if is_expr_diagnostic_item(cx, func1, sym::ptr_null);
49+
then {
50+
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
51+
return true;
52+
}
53+
}
54+
55+
// FIXME:
56+
// Also catch transmutations of variables which are known nulls.
57+
// To do this, MIR const propagation seems to be the better tool.
58+
// Whenever MIR const prop routines are more developed, this will
59+
// become available. As of this writing (25/03/19) it is not yet.
60+
false
61+
}

clippy_lints/src/transmuting_null.rs

Lines changed: 0 additions & 89 deletions
This file was deleted.

0 commit comments

Comments
 (0)