Skip to content

Commit 1fb50a5

Browse files
Add a Lint for Pointer to Integer Transmutes in Consts
1 parent 5d9b908 commit 1fb50a5

File tree

7 files changed

+93
-2
lines changed

7 files changed

+93
-2
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+35
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ declare_lint_pass! {
8282
PRIVATE_INTERFACES,
8383
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
8484
PTR_CAST_ADD_AUTO_TO_OBJECT,
85+
PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
8586
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
8687
REDUNDANT_IMPORTS,
8788
REDUNDANT_LIFETIMES,
@@ -5095,3 +5096,37 @@ declare_lint! {
50955096
reference: "issue #124535 <https://github.com/rust-lang/rust/issues/124535>",
50965097
};
50975098
}
5099+
5100+
declare_lint! {
5101+
/// The `ptr_to_integer_transmute_in_consts` lint detects pointer to integer
5102+
/// transmute in const functions and associated constants.
5103+
///
5104+
/// ### Example
5105+
///
5106+
/// ```rust,compile_fail
5107+
/// const fn foo(ptr: *const u8) -> usize {
5108+
/// unsafe {
5109+
/// std::mem::transmute::<*const u8, usize>(ptr)
5110+
/// }
5111+
/// }
5112+
/// ```
5113+
///
5114+
/// {{produces}}
5115+
///
5116+
/// ### Explanation
5117+
///
5118+
/// Transmuting pointers to integers in a `const` context is undefined behavior.
5119+
/// Any attempt to use the resulting integer will abort const-evaluation.
5120+
///
5121+
/// But sometimes the compiler might not emit an error for pointer to integer transmutes
5122+
/// inside const functions and associated consts because they are evaluated only when referenced.
5123+
/// Therefore, this lint serves as an extra layer of defense to prevent any undefined behavior
5124+
/// from compiling without any warnings or errors.
5125+
///
5126+
/// See [std::mem::transmute] in the reference for more details.
5127+
///
5128+
/// [std::mem::transmute]: https://doc.rust-lang.org/std/mem/fn.transmute.html
5129+
pub PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS,
5130+
Deny,
5131+
"detects attempts to transmute a pointer to integer in const context",
5132+
}

compiler/rustc_mir_transform/messages.ftl

+5
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,8 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned
2727
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
2828
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
2929
.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)
30+
31+
mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval
32+
.note = at compile-time, pointers do not have an integer value
33+
.note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
34+
.help = for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html

compiler/rustc_mir_transform/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,10 @@ pub(crate) struct MustNotSuspendReason {
121121
pub span: Span,
122122
pub reason: String,
123123
}
124+
125+
#[derive(LintDiagnostic)]
126+
#[diag(mir_transform_undefined_transmute)]
127+
#[note]
128+
#[note(mir_transform_note2)]
129+
#[help]
130+
pub(crate) struct UndefinedTransmute;

compiler/rustc_mir_transform/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ mod add_subtyping_projections;
5151
mod check_alignment;
5252
mod check_const_item_mutation;
5353
mod check_packed_ref;
54+
mod check_undefined_transmutes;
5455
// This pass is public to allow external drivers to perform MIR cleanup
5556
pub mod cleanup_post_borrowck;
5657
mod copy_prop;
@@ -293,6 +294,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
293294
&Lint(check_packed_ref::CheckPackedRef),
294295
&Lint(check_const_item_mutation::CheckConstItemMutation),
295296
&Lint(function_item_references::FunctionItemReferences),
297+
&Lint(check_undefined_transmutes::CheckUndefinedTransmutes),
296298
// What we need to do constant evaluation.
297299
&simplify::SimplifyCfg::Initial,
298300
&Lint(sanity_check::SanityCheck),

library/core/src/ptr/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1917,6 +1917,7 @@ pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
19171917
///
19181918
/// Any questions go to @nagisa.
19191919
#[lang = "align_offset"]
1920+
#[allow(ptr_to_integer_transmute_in_consts)]
19201921
pub(crate) const unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
19211922
// FIXME(#75598): Direct use of these intrinsics improves codegen significantly at opt-level <=
19221923
// 1, where the method versions of these operations are not inlined.

tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const fn zoom(ptr: *const u8) -> usize {
6262
//~^ ERROR pointers cannot be transmuted to integers
6363
}
6464
}
65-
65+
6666
fn main() {
6767
const a: u8 = 10;
6868
const value: usize = zoom(&a);

tests/ui/consts/const-eval/ptr-to-int-transmute-in-consts-issue-87525.stderr

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
error: pointers cannot be transmuted to integers during const eval
2+
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:61:9
3+
|
4+
LL | std::mem::transmute(ptr)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: at compile-time, pointers do not have an integer value
8+
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
9+
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
10+
= note: `#[deny(ptr_to_integer_transmute_in_consts)]` on by default
11+
112
error[E0080]: evaluation of constant value failed
213
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:68:26
314
|
@@ -7,6 +18,36 @@ LL | const value: usize = zoom(&a);
718
= help: this code performed an operation that depends on the underlying bytes representing a pointer
819
= help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
920

10-
error: aborting due to 1 previous error
21+
error: pointers cannot be transmuted to integers during const eval
22+
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:3:9
23+
|
24+
LL | std::mem::transmute(ptr)
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^
26+
|
27+
= note: at compile-time, pointers do not have an integer value
28+
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
29+
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
30+
31+
error: pointers cannot be transmuted to integers during const eval
32+
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:13:13
33+
|
34+
LL | std::mem::transmute(ptr)
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^
36+
|
37+
= note: at compile-time, pointers do not have an integer value
38+
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
39+
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
40+
41+
error: pointers cannot be transmuted to integers during const eval
42+
--> $DIR/ptr-to-int-transmute-in-consts-issue-87525.rs:30:13
43+
|
44+
LL | std::mem::transmute(ptr)
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^
46+
|
47+
= note: at compile-time, pointers do not have an integer value
48+
= note: avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior
49+
= help: for more information, see https://doc.rust-lang.org/std/mem/fn.transmute.html
50+
51+
error: aborting due to 5 previous errors
1152

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

0 commit comments

Comments
 (0)