add lint deref_nullptr
This commit is contained in:
parent
5c897d430d
commit
389100921a
4 changed files with 94 additions and 0 deletions
|
@ -2961,3 +2961,92 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `deref_nullptr` lint detects when an null pointer is dereferenced,
|
||||||
|
/// which causes [undefined behavior].
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// let x: i32 = unsafe {
|
||||||
|
/// *ptr::null()
|
||||||
|
/// };
|
||||||
|
/// ```
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// unsafe {
|
||||||
|
/// *(0 as *const i32);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// Dereferencing a null pointer causes [undefined behavior] even as a place expression,
|
||||||
|
/// like `&*(0 as *const i32)` or `addr_of!(*(0 as *const i32))`.
|
||||||
|
///
|
||||||
|
/// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
|
||||||
|
pub DEREF_NULLPTR,
|
||||||
|
Warn,
|
||||||
|
"detects when an null pointer is dereferenced"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(DerefNullPtr => [DEREF_NULLPTR]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for DerefNullPtr {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
|
||||||
|
/// test if expression is a null ptr
|
||||||
|
fn is_null_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
|
||||||
|
match &expr.kind {
|
||||||
|
rustc_hir::ExprKind::Cast(ref expr, ref ty) => {
|
||||||
|
if let rustc_hir::TyKind::Ptr(_) = ty.kind {
|
||||||
|
return is_zero(expr) || is_null_ptr(cx, expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for call to `core::ptr::null` or `core::ptr::null_mut`
|
||||||
|
rustc_hir::ExprKind::Call(ref path, _) => {
|
||||||
|
if let rustc_hir::ExprKind::Path(ref qpath) = path.kind {
|
||||||
|
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() {
|
||||||
|
return cx.tcx.is_diagnostic_item(sym::ptr_null, def_id)
|
||||||
|
|| cx.tcx.is_diagnostic_item(sym::ptr_null_mut, def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// test if experssion is the literal `0`
|
||||||
|
fn is_zero(expr: &hir::Expr<'_>) -> bool {
|
||||||
|
match &expr.kind {
|
||||||
|
rustc_hir::ExprKind::Lit(ref lit) => {
|
||||||
|
if let LitKind::Int(a, _) = lit.node {
|
||||||
|
return a == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rustc_hir::ExprKind::Unary(ref un_op, ref expr_deref) = expr.kind {
|
||||||
|
if let rustc_hir::UnOp::Deref = un_op {
|
||||||
|
if is_null_ptr(cx, expr_deref) {
|
||||||
|
cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
|
||||||
|
let mut err =
|
||||||
|
lint.build("Dereferencing a null pointer causes undefined behavior");
|
||||||
|
err.span_label(expr.span, "a null pointer is dereferenced");
|
||||||
|
err.span_label(
|
||||||
|
expr.span,
|
||||||
|
"this code causes undefined behavior when executed",
|
||||||
|
);
|
||||||
|
err.emit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -206,6 +206,7 @@ macro_rules! late_lint_mod_passes {
|
||||||
UnreachablePub: UnreachablePub,
|
UnreachablePub: UnreachablePub,
|
||||||
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
|
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
|
||||||
InvalidValue: InvalidValue,
|
InvalidValue: InvalidValue,
|
||||||
|
DerefNullPtr: DerefNullPtr,
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -900,6 +900,8 @@ symbols! {
|
||||||
profiler_runtime,
|
profiler_runtime,
|
||||||
ptr_guaranteed_eq,
|
ptr_guaranteed_eq,
|
||||||
ptr_guaranteed_ne,
|
ptr_guaranteed_ne,
|
||||||
|
ptr_null,
|
||||||
|
ptr_null_mut,
|
||||||
ptr_offset_from,
|
ptr_offset_from,
|
||||||
pub_macro_rules,
|
pub_macro_rules,
|
||||||
pub_restricted,
|
pub_restricted,
|
||||||
|
|
|
@ -211,6 +211,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_promotable]
|
#[rustc_promotable]
|
||||||
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
|
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
|
||||||
|
#[rustc_diagnostic_item = "ptr_null"]
|
||||||
pub const fn null<T>() -> *const T {
|
pub const fn null<T>() -> *const T {
|
||||||
0 as *const T
|
0 as *const T
|
||||||
}
|
}
|
||||||
|
@ -229,6 +230,7 @@ pub const fn null<T>() -> *const T {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
#[rustc_promotable]
|
#[rustc_promotable]
|
||||||
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
|
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
|
||||||
|
#[rustc_diagnostic_item = "ptr_null_mut"]
|
||||||
pub const fn null_mut<T>() -> *mut T {
|
pub const fn null_mut<T>() -> *mut T {
|
||||||
0 as *mut T
|
0 as *mut T
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue