1use rustc_hiras hir;
2use rustc_session::{declare_lint, declare_lint_pass};
34use crate::lints::{LossyProvenanceInt2Ptr, LossyProvenanceInt2PtrSuggestion};
5use crate::{LateContext, LateLintPass};
67#[doc =
r" The `fuzzy_provenance_casts` lint detects an `as` cast between an integer"]
#[doc = r" and a pointer."]
#[doc = r""]
#[doc = r" ### Example"]
#[doc = r""]
#[doc = r" ```rust"]
#[doc = r" #![feature(strict_provenance_lints)]"]
#[doc = r" #![warn(fuzzy_provenance_casts)]"]
#[doc = r""]
#[doc = r" fn main() {"]
#[doc = r" let _dangling = 16_usize as *const u8;"]
#[doc = r" }"]
#[doc = r" ```"]
#[doc = r""]
#[doc = r" {{produces}}"]
#[doc = r""]
#[doc = r" ### Explanation"]
#[doc = r""]
#[doc =
r" This lint is part of the strict provenance effort, see [issue #95228]."]
#[doc =
r" Casting an integer to a pointer is considered bad style, as a pointer"]
#[doc =
r" contains, besides the *address* also a *provenance*, indicating what"]
#[doc =
r" memory the pointer is allowed to read/write. Casting an integer, which"]
#[doc =
r" doesn't have provenance, to a pointer requires the compiler to assign"]
#[doc =
r#" (guess) provenance. The compiler assigns "all exposed valid" (see the"#]
#[doc =
r" docs of [`ptr::with_exposed_provenance`] for more information about this"]
#[doc =
r#" "exposing"). This penalizes the optimiser and is not well suited for"#]
#[doc = r" dynamic analysis/dynamic program verification (e.g. Miri or CHERI"]
#[doc = r" platforms)."]
#[doc = r""]
#[doc =
r" It is much better to use [`ptr::with_addr`] instead to specify the"]
#[doc =
r" provenance you want. If using this function is not possible because the"]
#[doc =
r" code relies on exposed provenance then there is as an escape hatch"]
#[doc = r" [`ptr::with_exposed_provenance`]."]
#[doc = r""]
#[doc = r" [issue #95228]: https://github.com/rust-lang/rust/issues/95228"]
#[doc =
r" [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr"]
#[doc =
r" [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html"]
pub static FUZZY_PROVENANCE_CASTS: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: "FUZZY_PROVENANCE_CASTS",
default_level: ::rustc_lint_defs::Allow,
desc: "a fuzzy integer to pointer cast is used",
is_externally_loaded: false,
feature_gate: Some(rustc_span::sym::strict_provenance_lints),
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_lint! {
8/// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
9 /// and a pointer.
10 ///
11 /// ### Example
12 ///
13 /// ```rust
14 /// #![feature(strict_provenance_lints)]
15 /// #![warn(fuzzy_provenance_casts)]
16 ///
17 /// fn main() {
18 /// let _dangling = 16_usize as *const u8;
19 /// }
20 /// ```
21 ///
22 /// {{produces}}
23 ///
24 /// ### Explanation
25 ///
26 /// This lint is part of the strict provenance effort, see [issue #95228].
27 /// Casting an integer to a pointer is considered bad style, as a pointer
28 /// contains, besides the *address* also a *provenance*, indicating what
29 /// memory the pointer is allowed to read/write. Casting an integer, which
30 /// doesn't have provenance, to a pointer requires the compiler to assign
31 /// (guess) provenance. The compiler assigns "all exposed valid" (see the
32 /// docs of [`ptr::with_exposed_provenance`] for more information about this
33 /// "exposing"). This penalizes the optimiser and is not well suited for
34 /// dynamic analysis/dynamic program verification (e.g. Miri or CHERI
35 /// platforms).
36 ///
37 /// It is much better to use [`ptr::with_addr`] instead to specify the
38 /// provenance you want. If using this function is not possible because the
39 /// code relies on exposed provenance then there is as an escape hatch
40 /// [`ptr::with_exposed_provenance`].
41 ///
42 /// [issue #95228]: https://github.com/rust-lang/rust/issues/95228
43 /// [`ptr::with_addr`]: https://doc.rust-lang.org/core/primitive.pointer.html#method.with_addr
44 /// [`ptr::with_exposed_provenance`]: https://doc.rust-lang.org/core/ptr/fn.with_exposed_provenance.html
45pub FUZZY_PROVENANCE_CASTS,
46 Allow,
47"a fuzzy integer to pointer cast is used",
48 @feature_gate = strict_provenance_lints;
49}5051#[doc = r" Lint for `as` casts between an integer and a pointer."]
pub struct FuzzyProvenanceCasts;
#[automatically_derived]
impl ::core::marker::Copy for FuzzyProvenanceCasts { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for FuzzyProvenanceCasts { }
#[automatically_derived]
impl ::core::clone::Clone for FuzzyProvenanceCasts {
#[inline]
fn clone(&self) -> FuzzyProvenanceCasts { *self }
}
impl ::rustc_lint_defs::LintPass for FuzzyProvenanceCasts {
fn name(&self) -> &'static str { "FuzzyProvenanceCasts" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[FUZZY_PROVENANCE_CASTS]))
}
}
impl FuzzyProvenanceCasts {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[FUZZY_PROVENANCE_CASTS]))
}
}declare_lint_pass!(
52/// Lint for `as` casts between an integer and a pointer.
53FuzzyProvenanceCasts => [FUZZY_PROVENANCE_CASTS]
54);
5556impl<'tcx> LateLintPass<'tcx> for FuzzyProvenanceCasts {
57fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
58let hir::ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind else { return };
5960let typeck_results = cx.typeck_results();
61// Only lint casts from integer to pointer
62let cast_from_ty = typeck_results.expr_ty(cast_from_expr);
63if !cast_from_ty.is_integral() {
64return;
65 }
66let cast_to_ty = typeck_results.expr_ty(expr);
67if !cast_to_ty.is_raw_ptr() {
68return;
69 }
7071let sugg =
72expr.span.can_be_used_for_suggestions().then(|| LossyProvenanceInt2PtrSuggestion {
73 lo: cast_from_expr.span.shrink_to_lo(),
74 hi: cast_from_expr.span.shrink_to_hi().to(cast_to_hir.span),
75 });
76let lint = LossyProvenanceInt2Ptr { expr_ty: cast_from_ty, cast_ty: cast_to_ty, sugg };
77cx.tcx.emit_node_span_lint(FUZZY_PROVENANCE_CASTS, expr.hir_id, expr.span, lint)
78 }
79}