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, LateLintPass, LintContext}
;
8 use rustc_middle
::lint
::in_external_macro
;
9 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
10 use rustc_span
::symbol
::sym
;
12 declare_clippy_lint
! {
14 /// Checks for transmute calls which would receive a null pointer.
16 /// ### Why is this bad?
17 /// Transmuting a null pointer is undefined behavior.
19 /// ### Known problems
20 /// Not all cases can be detected at the moment of this writing.
21 /// For example, variables which hold a null pointer and are then fed to a `transmute`
22 /// call, aren't detectable yet.
26 /// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
30 "transmutes from a null pointer to a reference, which is undefined behavior"
33 declare_lint_pass
!(TransmutingNull
=> [TRANSMUTING_NULL
]);
35 const LINT_MSG
: &str = "transmuting a known null pointer into a reference";
37 impl<'tcx
> LateLintPass
<'tcx
> for TransmutingNull
{
38 fn check_expr(&mut self, cx
: &LateContext
<'tcx
>, expr
: &'tcx Expr
<'_
>) {
39 if in_external_macro(cx
.sess(), expr
.span
) {
44 if let ExprKind
::Call(func
, [arg
]) = expr
.kind
;
45 if is_expr_diagnostic_item(cx
, func
, sym
::transmute
);
48 // Catching transmute over constants that resolve to `null`.
49 let mut const_eval_context
= constant_context(cx
, cx
.typeck_results());
51 if let ExprKind
::Path(ref _qpath
) = arg
.kind
;
52 let x
= const_eval_context
.expr(arg
);
53 if let Some(Constant
::RawPtr(0)) = x
;
55 span_lint(cx
, TRANSMUTING_NULL
, expr
.span
, LINT_MSG
)
60 // `std::mem::transmute(0 as *const i32)`
62 if let ExprKind
::Cast(inner_expr
, _cast_ty
) = arg
.kind
;
63 if let ExprKind
::Lit(ref lit
) = inner_expr
.kind
;
64 if let LitKind
::Int(0, _
) = lit
.node
;
66 span_lint(cx
, TRANSMUTING_NULL
, expr
.span
, LINT_MSG
)
71 // `std::mem::transmute(std::ptr::null::<i32>())`
73 if let ExprKind
::Call(func1
, []) = arg
.kind
;
74 if is_expr_diagnostic_item(cx
, func1
, sym
::ptr_null
);
76 span_lint(cx
, TRANSMUTING_NULL
, expr
.span
, LINT_MSG
)
81 // Also catch transmutations of variables which are known nulls.
82 // To do this, MIR const propagation seems to be the better tool.
83 // Whenever MIR const prop routines are more developed, this will
84 // become available. As of this writing (25/03/19) it is not yet.