Skip to content

Commit 1040cab

Browse files
Gankraniluxv
authored andcommitted
WIP PROOF-OF-CONCEPT: Make the compiler complain about all int<->ptr casts.
ALL OF THEM
1 parent e4f5b15 commit 1040cab

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+36
Original file line numberDiff line numberDiff line change
@@ -2648,6 +2648,41 @@ declare_lint! {
26482648
};
26492649
}
26502650

2651+
declare_lint! {
2652+
/// The `fuzzy_provenance_casts` lint detects an `as` cast between an integer
2653+
/// and a pointer.
2654+
///
2655+
/// ### Example
2656+
///
2657+
/// fn main() {
2658+
/// let my_ref = &0;
2659+
/// let my_addr = my_ref as usize;
2660+
/// }
2661+
/// ```
2662+
///
2663+
/// {{produces}}
2664+
///
2665+
/// ### Explanation
2666+
///
2667+
/// Casting a pointer to an integer or an integer to a pointer is a lossy operation,
2668+
/// because beyond just an *address* a pointer may be associated with a particular
2669+
/// *provenance* and *segment*. This information is required by both the compiler
2670+
/// and the hardware to correctly execute your code. If you need to do this kind
2671+
/// of operation, use ptr::addr and ptr::with_addr.
2672+
///
2673+
/// This is a [future-incompatible] lint to transition this to a hard error
2674+
/// in the future. See [issue #9999999] for more details.
2675+
///
2676+
/// [future-incompatible]: ../index.md#future-incompatible-lints
2677+
/// [issue #9999999]: https://github.com/rust-lang/rust/issues/9999999
2678+
pub FUZZY_PROVENANCE_CASTS,
2679+
Warn,
2680+
"A lossy pointer-integer integer cast is used",
2681+
@future_incompatible = FutureIncompatibleInfo {
2682+
reference: "issue #9999999 <https://github.com/rust-lang/rust/issues/9999999>",
2683+
};
2684+
}
2685+
26512686
declare_lint! {
26522687
/// The `const_evaluatable_unchecked` lint detects a generic constant used
26532688
/// in a type.
@@ -3101,6 +3136,7 @@ declare_lint_pass! {
31013136
UNSAFE_OP_IN_UNSAFE_FN,
31023137
INCOMPLETE_INCLUDE,
31033138
CENUM_IMPL_DROP_CAST,
3139+
FUZZY_PROVENANCE_CASTS,
31043140
CONST_EVALUATABLE_UNCHECKED,
31053141
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
31063142
MUST_NOT_SUSPEND,

compiler/rustc_typeck/src/check/cast.rs

+60-4
Original file line numberDiff line numberDiff line change
@@ -807,11 +807,22 @@ impl<'a, 'tcx> CastCheck<'tcx> {
807807

808808
// ptr -> *
809809
(Ptr(m_e), Ptr(m_c)) => self.check_ptr_ptr_cast(fcx, m_e, m_c), // ptr-ptr-cast
810-
(Ptr(m_expr), Int(_)) => self.check_ptr_addr_cast(fcx, m_expr), // ptr-addr-cast
811-
(FnPtr, Int(_)) => Ok(CastKind::FnPtrAddrCast),
812810

813-
// * -> ptr
814-
(Int(_), Ptr(mt)) => self.check_addr_ptr_cast(fcx, mt), // addr-ptr-cast
811+
// ptr-addr-cast
812+
(Ptr(m_expr), Int(_)) => {
813+
self.fuzzy_provenance_ptr2int_lint(fcx, t_from);
814+
self.check_ptr_addr_cast(fcx, m_expr)
815+
}
816+
(FnPtr, Int(_)) => {
817+
self.fuzzy_provenance_ptr2int_lint(fcx, t_from);
818+
Ok(CastKind::FnPtrAddrCast)
819+
}
820+
// addr-ptr-cast
821+
(Int(_), Ptr(mt)) => {
822+
self.fuzzy_provenance_int2ptr_lint(fcx);
823+
self.check_addr_ptr_cast(fcx, mt)
824+
}
825+
// fn-ptr-cast
815826
(FnPtr, Ptr(mt)) => self.check_fptr_ptr_cast(fcx, mt),
816827

817828
// prim -> prim
@@ -934,6 +945,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
934945
fcx: &FnCtxt<'a, 'tcx>,
935946
m_cast: TypeAndMut<'tcx>,
936947
) -> Result<CastKind, CastError> {
948+
self.fuzzy_provenance_int2ptr_lint(fcx);
937949
// ptr-addr cast. pointer must be thin.
938950
match fcx.pointer_kind(m_cast.ty, self.span)? {
939951
None => Err(CastError::UnknownCastPtrKind),
@@ -973,6 +985,50 @@ impl<'a, 'tcx> CastCheck<'tcx> {
973985
}
974986
}
975987
}
988+
989+
fn fuzzy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_from: CastTy<'tcx>) {
990+
fcx.tcx.struct_span_lint_hir(
991+
lint::builtin::FUZZY_PROVENANCE_CASTS,
992+
self.expr.hir_id,
993+
self.span,
994+
|err| {
995+
let mut err = err.build(&format!(
996+
"strict provenance disallows casting pointer `{}` to integer `{}`",
997+
self.expr_ty, self.cast_ty
998+
));
999+
1000+
if let CastTy::FnPtr = t_from {
1001+
err.help(
1002+
"use `(... as *const u8).addr()` to obtain \
1003+
the address of a function pointer",
1004+
);
1005+
} else {
1006+
err.help("use `.addr()` to obtain the address of a pointer");
1007+
}
1008+
1009+
err.emit();
1010+
},
1011+
);
1012+
}
1013+
1014+
fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, 'tcx>) {
1015+
fcx.tcx.struct_span_lint_hir(
1016+
lint::builtin::FUZZY_PROVENANCE_CASTS,
1017+
self.expr.hir_id,
1018+
self.span,
1019+
|err| {
1020+
err.build(&format!(
1021+
"strict provenance disallows casting integer `{}` to pointer `{}`",
1022+
self.expr_ty, self.cast_ty
1023+
))
1024+
.help(
1025+
"use `.with_addr(...)` to adjust a valid pointer \
1026+
in the same allocation, to this address",
1027+
)
1028+
.emit();
1029+
},
1030+
);
1031+
}
9761032
}
9771033

9781034
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

0 commit comments

Comments
 (0)