Skip to content

Commit 570601f

Browse files
committed
Auto merge of #114757 - Urgau:transmute-with-invalid_reference_casting, r=est31
Also consider `mem::transmute` with the `invalid_reference_casting` lint This PR extend the `invalid_reference_casting` lint with regard to the `std::mem::transmute` function. ``` error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell` --> $DIR/reference_casting.rs:27:16 | LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(&num); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``` *I encourage anyone reviewing this PR to do so [without whitespaces](https://github.blog/2011-10-21-github-secrets/#whitespace).*
2 parents 5f3abbc + b517dd5 commit 570601f

File tree

3 files changed

+74
-33
lines changed

3 files changed

+74
-33
lines changed

compiler/rustc_lint/src/reference_casting.rs

+48-24
Original file line numberDiff line numberDiff line change
@@ -98,32 +98,56 @@ impl<'tcx> LateLintPass<'tcx> for InvalidReferenceCasting {
9898
fn is_cast_from_const_to_mut<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
9999
let e = e.peel_blocks();
100100

101-
// <expr> as *mut ...
102-
let e = if let ExprKind::Cast(e, t) = e.kind
103-
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
104-
e
105-
// <expr>.cast_mut()
106-
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
107-
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
108-
&& cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
109-
expr
110-
} else {
111-
return false;
112-
};
101+
fn from_casts<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
102+
// <expr> as *mut ...
103+
let e = if let ExprKind::Cast(e, t) = e.kind
104+
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
105+
e
106+
// <expr>.cast_mut()
107+
} else if let ExprKind::MethodCall(_, expr, [], _) = e.kind
108+
&& let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
109+
&& cx.tcx.is_diagnostic_item(sym::ptr_cast_mut, def_id) {
110+
expr
111+
} else {
112+
return None;
113+
};
113114

114-
let e = e.peel_blocks();
115+
let e = e.peel_blocks();
116+
117+
// <expr> as *const ...
118+
let e = if let ExprKind::Cast(e, t) = e.kind
119+
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
120+
e
121+
// ptr::from_ref(<expr>)
122+
} else if let ExprKind::Call(path, [arg]) = e.kind
123+
&& let ExprKind::Path(ref qpath) = path.kind
124+
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
125+
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
126+
arg
127+
} else {
128+
return None;
129+
};
130+
131+
Some(e)
132+
}
133+
134+
fn from_transmute<'tcx>(
135+
cx: &LateContext<'tcx>,
136+
e: &'tcx Expr<'tcx>,
137+
) -> Option<&'tcx Expr<'tcx>> {
138+
// mem::transmute::<_, *mut _>(<expr>)
139+
if let ExprKind::Call(path, [arg]) = e.kind
140+
&& let ExprKind::Path(ref qpath) = path.kind
141+
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
142+
&& cx.tcx.is_diagnostic_item(sym::transmute, def_id)
143+
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Mut, .. }) = cx.typeck_results().node_type(e.hir_id).kind() {
144+
Some(arg)
145+
} else {
146+
None
147+
}
148+
}
115149

116-
// <expr> as *const ...
117-
let e = if let ExprKind::Cast(e, t) = e.kind
118-
&& let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) = cx.typeck_results().node_type(t.hir_id).kind() {
119-
e
120-
// ptr::from_ref(<expr>)
121-
} else if let ExprKind::Call(path, [arg]) = e.kind
122-
&& let ExprKind::Path(ref qpath) = path.kind
123-
&& let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
124-
&& cx.tcx.is_diagnostic_item(sym::ptr_from_ref, def_id) {
125-
arg
126-
} else {
150+
let Some(e) = from_casts(cx, e).or_else(|| from_transmute(cx, e)) else {
127151
return false;
128152
};
129153

tests/ui/lint/reference_casting.rs

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ unsafe fn ref_to_mut() {
2424
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
2525
let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
2626
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
27+
let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
28+
//~^ ERROR casting `&T` to `&mut T` is undefined behavior
2729

2830
let deferred = num as *const i32 as *mut i32;
2931
let _num = &mut *deferred;
@@ -47,6 +49,9 @@ unsafe fn assign_to_ref() {
4749
//~^ ERROR assigning to `&T` is undefined behavior
4850
*(std::ptr::from_ref({ num }) as *mut i32) += 1;
4951
//~^ ERROR assigning to `&T` is undefined behavior
52+
*std::mem::transmute::<_, *mut i32>(num) += 1;
53+
//~^ ERROR assigning to `&T` is undefined behavior
54+
5055
let value = num as *const i32 as *mut i32;
5156
*value = 1;
5257
//~^ ERROR assigning to `&T` is undefined behavior

tests/ui/lint/reference_casting.stderr

+21-9
Original file line numberDiff line numberDiff line change
@@ -37,56 +37,68 @@ LL | let _num = &mut *(std::ptr::from_ref({ num }) as *mut i32);
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3838

3939
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
40-
--> $DIR/reference_casting.rs:29:16
40+
--> $DIR/reference_casting.rs:27:16
41+
|
42+
LL | let _num = &mut *std::mem::transmute::<_, *mut i32>(num);
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44+
45+
error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
46+
--> $DIR/reference_casting.rs:31:16
4147
|
4248
LL | let deferred = num as *const i32 as *mut i32;
4349
| ----------------------------- casting happend here
4450
LL | let _num = &mut *deferred;
4551
| ^^^^^^^^^^^^^^
4652

4753
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
48-
--> $DIR/reference_casting.rs:38:5
54+
--> $DIR/reference_casting.rs:40:5
4955
|
5056
LL | *(a as *const _ as *mut _) = String::from("Replaced");
5157
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5258

5359
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
54-
--> $DIR/reference_casting.rs:40:5
60+
--> $DIR/reference_casting.rs:42:5
5561
|
5662
LL | *(a as *const _ as *mut String) += " world";
5763
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5864

5965
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
60-
--> $DIR/reference_casting.rs:42:5
66+
--> $DIR/reference_casting.rs:44:5
6167
|
6268
LL | *std::ptr::from_ref(num).cast_mut() += 1;
6369
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6470

6571
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
66-
--> $DIR/reference_casting.rs:44:5
72+
--> $DIR/reference_casting.rs:46:5
6773
|
6874
LL | *std::ptr::from_ref({ num }).cast_mut() += 1;
6975
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7076

7177
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
72-
--> $DIR/reference_casting.rs:46:5
78+
--> $DIR/reference_casting.rs:48:5
7379
|
7480
LL | *{ std::ptr::from_ref(num) }.cast_mut() += 1;
7581
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
7682

7783
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
78-
--> $DIR/reference_casting.rs:48:5
84+
--> $DIR/reference_casting.rs:50:5
7985
|
8086
LL | *(std::ptr::from_ref({ num }) as *mut i32) += 1;
8187
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8288

8389
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
84-
--> $DIR/reference_casting.rs:51:5
90+
--> $DIR/reference_casting.rs:52:5
91+
|
92+
LL | *std::mem::transmute::<_, *mut i32>(num) += 1;
93+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
94+
95+
error: assigning to `&T` is undefined behavior, consider using an `UnsafeCell`
96+
--> $DIR/reference_casting.rs:56:5
8597
|
8698
LL | let value = num as *const i32 as *mut i32;
8799
| ----------------------------- casting happend here
88100
LL | *value = 1;
89101
| ^^^^^^^^^^
90102

91-
error: aborting due to 14 previous errors
103+
error: aborting due to 16 previous errors
92104

0 commit comments

Comments
 (0)