Skip to content

Commit cec4254

Browse files
committed
Implement new lint for detecting buggy pointer-to-int casts
New lint `invalid_ptr_to_int_cast` detects pointer (or function) to integer casts when the integer is not usize (or u64), and suggests going through usize, e.g. `x as usize as u32`. See #81686 for motivation. Closes #81686
1 parent cb17136 commit cec4254

File tree

8 files changed

+382
-41
lines changed

8 files changed

+382
-41
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+41
Original file line numberDiff line numberDiff line change
@@ -2876,6 +2876,46 @@ declare_lint! {
28762876
};
28772877
}
28782878

2879+
declare_lint! {
2880+
/// The `invalid_ptr_to_int_cast` lint triggers if a pointer is cast to any integer type other
2881+
/// than `usize` or `u64`, since doing so is often a bug.
2882+
///
2883+
/// ### Example
2884+
///
2885+
/// ```rust,compile_fail
2886+
/// #![deny(invalid_ptr_to_int_cast)]
2887+
///
2888+
/// fn main() {
2889+
/// let x = 100_000_000;
2890+
/// let y = u16::max as u32; // the user meant the constant `u16::MAX`, rather than the
2891+
/// // function `u16::max`, but this cast is technically permitted,
2892+
/// // so will not produce an error
2893+
/// println!("{}", x > y); // prints `false` (unexpectedly)
2894+
/// }
2895+
/// ```
2896+
///
2897+
/// {{produces}}
2898+
///
2899+
/// ### Explanation
2900+
///
2901+
/// The example above shows how a user might accidentally cast a function pointer (rather than
2902+
/// an integer constant) to an integer type other than `usize` or `u64`. Though this is
2903+
/// currently permitted by Rust, there is very little reason to cast a pointer to any integer
2904+
/// other than a `usize` or `u64`. Therefore, any instances of such casts are likely to be
2905+
/// bugs.
2906+
///
2907+
/// This lint warns against those cases.
2908+
///
2909+
/// In the future, we may want to make this a hard error.
2910+
///
2911+
/// To cast a pointer to an integer type other than `usize` or `u64` without triggering the
2912+
/// lint, you can first cast to a `usize` and then to the integer type, e.g. `ptr as usize as
2913+
/// u32`.
2914+
pub INVALID_PTR_TO_INT_CAST,
2915+
Allow,
2916+
"detects pointers casts to integer types other than `usize` or `u64`",
2917+
}
2918+
28792919
declare_lint_pass! {
28802920
/// Does nothing as a lint pass, but registers some `Lint`s
28812921
/// that are used by other parts of the compiler.
@@ -2960,6 +3000,7 @@ declare_lint_pass! {
29603000
LEGACY_DERIVE_HELPERS,
29613001
PROC_MACRO_BACK_COMPAT,
29623002
OR_PATTERNS_BACK_COMPAT,
3003+
INVALID_PTR_TO_INT_CAST,
29633004
]
29643005
}
29653006

compiler/rustc_middle/src/ty/sty.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1946,6 +1946,11 @@ impl<'tcx> TyS<'tcx> {
19461946
matches!(self.kind(), FnPtr(_))
19471947
}
19481948

1949+
#[inline]
1950+
pub fn is_raw_ptr(&self) -> bool {
1951+
matches!(self.kind(), RawPtr(_))
1952+
}
1953+
19491954
#[inline]
19501955
pub fn is_impl_trait(&self) -> bool {
19511956
matches!(self.kind(), Opaque(..))

0 commit comments

Comments
 (0)