Skip to content

Commit

Permalink
Add a Lint for Pointer to Integer Transmutes in Consts
Browse files Browse the repository at this point in the history
  • Loading branch information
veera-sivarajan committed Sep 25, 2024
1 parent 5d9b908 commit 7867a29
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 2 deletions.
35 changes: 35 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ declare_lint_pass! {
PRIVATE_INTERFACES,
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
PTR_CAST_ADD_AUTO_TO_OBJECT,
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
REDUNDANT_IMPORTS,
REDUNDANT_LIFETIMES,
Expand Down Expand Up @@ -5095,3 +5096,37 @@ declare_lint! {
reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
};
}

declare_lint! {
/// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
/// transmute in const functions and associated constants.
///
/// ### Example
///
/// ```rust,compile_fail
/// const fn foo(ptr: *const u8) -> usize {
/// unsafe {
/// std::mem::transmute::<*const u8, usize>(ptr)
/// }
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Transmuting pointers to integers in a `const` context is undefined behavior.
/// Any attempt to use the resulting integer will abort const-evaluation.
///
/// But sometimes the compiler might not emit an error for pointer to integer transmutes
/// inside const functions and associated consts because they are evaluated only when referenced.
/// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior
/// from compiling without any warnings or errors.
///
/// See [std::mem::transmute] in the reference for more details.
///
/// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html
pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
Deny,
"detects attempts to transmute a pointer to integer in const context",
}
5 changes: 5 additions & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
.help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval
.note = at compile-time, pointers do not have an integer value
.note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
7 changes: 7 additions & 0 deletions compiler/rustc_mir_transform/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,10 @@ pub(crate) struct MustNotSuspendReason {
pub span: Span,
pub reason: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_undefined_transmute)]
#[note]
#[note(mir_transform_note2)]
#[help]
pub(crate) struct UndefinedTransmute;
2 changes: 2 additions & 0 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ mod add_subtyping_projections;
mod check_alignment;
mod check_const_item_mutation;
mod check_packed_ref;
mod check_undefined_transmutes;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod cleanup_post_borrowck;
mod copy_prop;
Expand Down Expand Up @@ -293,6 +294,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
&Lint(check_packed_ref::CheckPackedRef),
&Lint(check_const_item_mutation::CheckConstItemMutation),
&Lint(function_item_references::FunctionItemReferences),
&Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
// What we need to do constant evaluation.
&simplify::SimplifyCfg::Initial,
&Lint(sanity_check::SanityCheck),
Expand Down
1 change: 1 addition & 0 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1916,6 +1916,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
/// than trying to adapt this to accommodate that change.
///
/// Any questions go to @nagisa.
#[cfg_attr(not(bootstrap), allow(ptr_to_integer_transmute_in_consts))]
#[lang = "align_offset"]
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const fn zoom(ptr: *const u8) -> usize {
//~^ ERROR pointers cannot be transmuted to integers
}
}

fn main() {
const a: u8 = 10;
const value: usize = zoom(&a);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
error: pointers cannot be transmuted to integers during const eval
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9
|
LL | std::mem::transmute(ptr)
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: at compile-time, pointers do not have an integer value
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
= note: `#[deny(ptr_to_integer_transmute_in_consts)]` on by default

error[E0080]: evaluation of constant value failed
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26
|
Expand All @@ -7,6 +18,36 @@ LL | const value: usize = zoom(&a);
= help: this code performed an operation that depends on the underlying bytes representing a pointer
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported

error: aborting due to 1 previous error
error: pointers cannot be transmuted to integers during const eval
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9
|
LL | std::mem::transmute(ptr)
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: at compile-time, pointers do not have an integer value
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

error: pointers cannot be transmuted to integers during const eval
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13
|
LL | std::mem::transmute(ptr)
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: at compile-time, pointers do not have an integer value
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

error: pointers cannot be transmuted to integers during const eval
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13
|
LL | std::mem::transmute(ptr)
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: at compile-time, pointers do not have an integer value
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0080`.

0 comments on commit 7867a29

Please sign in to comment.