WIP PROOF-OF-CONCEPT: Make the compiler complain about all int<->ptr casts.

ALL

OF

THEM
This commit is contained in:
Aria Beingessner 2022-03-21 19:25:44 -04:00 committed by niluxv
parent e4f5b15b88
commit 1040cab53b
2 changed files with 96 additions and 4 deletions

View File

@ -2648,6 +2648,41 @@ declare_lint! {
};
}
declare_lint! {
/// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
/// and a pointer.
///
/// ### Example
///
/// fn main() {
/// let my_ref = &0;
/// let my_addr = my_ref as usize;
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Casting a pointer to an integer or an integer to a pointer is a lossy operation,
/// because beyond just an *address* a pointer may be associated with a particular
/// *provenance* and *segment*. This information is required by both the compiler
/// and the hardware to correctly execute your code. If you need to do this kind
/// of operation, use ptr::addr and ptr::with_addr.
///
/// This is a [future-incompatible] lint to transition this to a hard error
/// in the future. See [issue #9999999] for more details.
///
/// [future-incompatible]: ../index.md#future-incompatible-lints
/// [issue #9999999]: https://github.com/rust-lang/rust/issues/9999999
pub FUZZY_PROVENANCE_CASTS,
Warn,
"A lossy pointer-integer integer cast is used",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #9999999 <https://github.com/rust-lang/rust/issues/9999999>",
};
}
declare_lint! {
/// The `const_evaluatable_unchecked` lint detects a generic constant used
/// in a type.
@ -3101,6 +3136,7 @@ declare_lint_pass! {
UNSAFE_OP_IN_UNSAFE_FN,
INCOMPLETE_INCLUDE,
CENUM_IMPL_DROP_CAST,
FUZZY_PROVENANCE_CASTS,
CONST_EVALUATABLE_UNCHECKED,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
MUST_NOT_SUSPEND,

View File

@ -807,11 +807,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
// ptr -> *
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
// * -> ptr
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
// ptr-addr-cast
(Ptr(m_expr), Int(_)) => {
self.fuzzy_provenance_ptr2int_lint(fcx, t_from);
self.check_ptr_addr_cast(fcx, m_expr)
}
(FnPtr, Int(_)) => {
self.fuzzy_provenance_ptr2int_lint(fcx, t_from);
Ok(CastKind::FnPtrAddrCast)
}
// addr-ptr-cast
(Int(_), Ptr(mt)) => {
self.fuzzy_provenance_int2ptr_lint(fcx);
self.check_addr_ptr_cast(fcx, mt)
}
// fn-ptr-cast
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
// prim -> prim
@ -934,6 +945,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fcx: &FnCtxt<'a, 'tcx>,
m_cast: TypeAndMut<'tcx>,
) -> Result<CastKind, CastError> {
self.fuzzy_provenance_int2ptr_lint(fcx);
// ptr-addr cast. pointer must be thin.
match fcx.pointer_kind(m_cast.ty, self.span)? {
None => Err(CastError::UnknownCastPtrKind),
@ -973,6 +985,50 @@ impl<'a, 'tcx> CastCheck<'tcx> {
}
}
}
fn fuzzy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_from: CastTy<'tcx>) {
fcx.tcx.struct_span_lint_hir(
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
let mut err = err.build(&format!(
"strict provenance disallows casting pointer `{}` to integer `{}`",
self.expr_ty, self.cast_ty
));
if let CastTy::FnPtr = t_from {
err.help(
"use `(... as *const u8).addr()` to obtain \
the address of a function pointer",
);
} else {
err.help("use `.addr()` to obtain the address of a pointer");
}
err.emit();
},
);
}
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
fcx.tcx.struct_span_lint_hir(
lint::builtin::FUZZY_PROVENANCE_CASTS,
self.expr.hir_id,
self.span,
|err| {
err.build(&format!(
"strict provenance disallows casting integer `{}` to pointer `{}`",
self.expr_ty, self.cast_ty
))
.help(
"use `.with_addr(...)` to adjust a valid pointer \
in the same allocation, to this address",
)
.emit();
},
);
}
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {