Skip to content

Commit 561dfaf

Browse files
committed
Implement a lint for implicit autoref of raw pointer dereference
1 parent 44fcfb0 commit 561dfaf

File tree

5 files changed

+141
-0
lines changed

5 files changed

+141
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use crate::{LateContext, LateLintPass, LintContext};
2+
3+
use rustc_errors::Applicability;
4+
use rustc_hir::{self as hir, Expr, ExprKind, UnOp};
5+
use rustc_middle::ty::adjustment::{Adjust, AutoBorrow};
6+
7+
declare_lint! {
8+
/// The `implicit_unsafe_autorefs` lint checks for implicitly taken references to dereferences of raw pointers.
9+
///
10+
/// ### Example
11+
///
12+
/// ```rust
13+
/// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
14+
/// addr_of_mut!((*ptr)[..16])
15+
/// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`,
16+
/// // implicitly creating a reference
17+
/// }
18+
/// ```
19+
///
20+
/// {{produces}}
21+
///
22+
/// ### Explanation
23+
///
24+
/// When working with raw pointers it's usually undesirable to create references,
25+
/// since they inflict a lot of safety requirement. Unfortunately, it's possible
26+
/// to take a reference to a dereferece of a raw pointer implitly, which inflicts
27+
/// the usual reference requirements without you even knowing that.
28+
///
29+
/// If you are sure, you can soundly take a reference, then you can take it explicitly:
30+
/// ```rust
31+
/// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
32+
/// addr_of_mut!((&mut *ptr)[..16])
33+
/// }
34+
/// ```
35+
///
36+
/// Otherwise try to find an alternative way to achive your goals that work only with
37+
/// raw pointers:
38+
/// ```rust
39+
/// #![feature(slice_ptr_get)]
40+
///
41+
/// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] {
42+
/// ptr.get_unchecked_mut(..16)
43+
/// }
44+
/// ```
45+
pub IMPLICIT_UNSAFE_AUTOREFS,
46+
Deny,
47+
"implicit reference to a dereference of a raw pointer"
48+
}
49+
50+
declare_lint_pass!(ImplicitUnsafeAutorefs => [IMPLICIT_UNSAFE_AUTOREFS]);
51+
52+
impl<'tcx> LateLintPass<'tcx> for ImplicitUnsafeAutorefs {
53+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
54+
let typeck = cx.typeck_results();
55+
let adjustments_table = typeck.adjustments();
56+
57+
if let Some(adjustments) = adjustments_table.get(expr.hir_id)
58+
&& let [adjustment] = &**adjustments
59+
// An auto-borrow
60+
&& let Adjust::Borrow(AutoBorrow::Ref(_, mutbl)) = adjustment.kind
61+
// ... of a deref
62+
&& let ExprKind::Unary(UnOp::Deref, dereferenced) = expr.kind
63+
// ... of a raw pointer
64+
&& typeck.expr_ty(dereferenced).is_unsafe_ptr()
65+
{
66+
let mutbl = hir::Mutability::prefix_str(&mutbl.into());
67+
68+
let msg = "implicit auto-ref creates a reference to a dereference of a raw pointer";
69+
cx.struct_span_lint(IMPLICIT_UNSAFE_AUTOREFS, expr.span, msg, |lint| {
70+
lint
71+
.note("creating a reference inflicts a lot of safety requirements")
72+
.multipart_suggestion(
73+
"if this reference is intentional, make it explicit",
74+
vec![
75+
(expr.span.shrink_to_lo(), format!("(&{mutbl}")),
76+
(expr.span.shrink_to_hi(), ")".to_owned())
77+
],
78+
Applicability::MaybeIncorrect
79+
)
80+
})
81+
}
82+
}
83+
}

compiler/rustc_lint/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ mod errors;
5454
mod expect;
5555
mod for_loops_over_fallibles;
5656
pub mod hidden_unicode_codepoints;
57+
mod implicit_unsafe_autorefs;
5758
mod internal;
5859
mod late;
5960
mod let_underscore;
@@ -89,6 +90,7 @@ use builtin::*;
8990
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
9091
use for_loops_over_fallibles::*;
9192
use hidden_unicode_codepoints::*;
93+
use implicit_unsafe_autorefs::*;
9294
use internal::*;
9395
use let_underscore::*;
9496
use methods::*;
@@ -191,6 +193,7 @@ macro_rules! late_lint_mod_passes {
191193
$args,
192194
[
193195
ForLoopsOverFallibles: ForLoopsOverFallibles,
196+
ImplicitUnsafeAutorefs: ImplicitUnsafeAutorefs,
194197
HardwiredLints: HardwiredLints,
195198
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
196199
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
use std::ptr::{addr_of, addr_of_mut};
3+
4+
unsafe fn _test_mut(ptr: *mut [u8]) -> *mut [u8] {
5+
addr_of_mut!((&mut (*ptr))[..16])
6+
//~^ error: implicit auto-ref creates a reference to a dereference of a raw pointer
7+
}
8+
9+
unsafe fn _test_const(ptr: *const [u8]) -> *const [u8] {
10+
addr_of!((&(*ptr))[..16])
11+
//~^ error: implicit auto-ref creates a reference to a dereference of a raw pointer
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// run-rustfix
2+
use std::ptr::{addr_of, addr_of_mut};
3+
4+
unsafe fn _test_mut(ptr: *mut [u8]) -> *mut [u8] {
5+
addr_of_mut!((*ptr)[..16])
6+
//~^ error: implicit auto-ref creates a reference to a dereference of a raw pointer
7+
}
8+
9+
unsafe fn _test_const(ptr: *const [u8]) -> *const [u8] {
10+
addr_of!((*ptr)[..16])
11+
//~^ error: implicit auto-ref creates a reference to a dereference of a raw pointer
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error: implicit auto-ref creates a reference to a dereference of a raw pointer
2+
--> $DIR/implicit_unsafe_autoref.rs:5:18
3+
|
4+
LL | addr_of_mut!((*ptr)[..16])
5+
| ^^^^^^
6+
|
7+
= note: creating a reference inflicts a lot of safety requirements
8+
= note: `#[deny(implicit_unsafe_autorefs)]` on by default
9+
help: if this reference is intentional, make it explicit
10+
|
11+
LL | addr_of_mut!((&mut (*ptr))[..16])
12+
| +++++ +
13+
14+
error: implicit auto-ref creates a reference to a dereference of a raw pointer
15+
--> $DIR/implicit_unsafe_autoref.rs:10:14
16+
|
17+
LL | addr_of!((*ptr)[..16])
18+
| ^^^^^^
19+
|
20+
= note: creating a reference inflicts a lot of safety requirements
21+
help: if this reference is intentional, make it explicit
22+
|
23+
LL | addr_of!((&(*ptr))[..16])
24+
| ++ +
25+
26+
error: aborting due to 2 previous errors
27+

0 commit comments

Comments
 (0)