}
}
}
+
+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();
+ });
+ }
+ }
+ }
+ }
+}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
+#[rustc_diagnostic_item = "ptr_null"]
pub const fn null<T>() -> *const T {
0 as *const T
}
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_promotable]
#[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 {
0 as *mut T
}