Skip to content

Commit c251120

Browse files
authored
Merge pull request #2400 from devonhollowood/misaligned-transmute
Add misaligned_transmute lint
2 parents 7812038 + 0413b3f commit c251120

File tree

5 files changed

+56
-4
lines changed

5 files changed

+56
-4
lines changed

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
603603
transmute::TRANSMUTE_PTR_TO_REF,
604604
transmute::USELESS_TRANSMUTE,
605605
transmute::WRONG_TRANSMUTE,
606+
transmute::MISALIGNED_TRANSMUTE,
606607
types::ABSURD_EXTREME_COMPARISONS,
607608
types::BORROWED_BOX,
608609
types::BOX_VEC,

clippy_lints/src/transmute.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use rustc::ty::{self, Ty};
33
use rustc::hir::*;
44
use std::borrow::Cow;
55
use syntax::ast;
6-
use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then};
6+
use utils::{last_path_segment, match_def_path, paths, snippet, span_lint, span_lint_and_then,
7+
alignment};
78
use utils::{opt_def_id, sugg};
89

910
/// **What it does:** Checks for transmutes that can't ever be correct on any
@@ -168,6 +169,23 @@ declare_lint! {
168169
"transmutes from an integer to a float"
169170
}
170171

172+
/// **What it does:** Checks for transmutes to a potentially less-aligned type.
173+
///
174+
/// **Why is this bad?** This might result in undefined behavior.
175+
///
176+
/// **Known problems:** None.
177+
///
178+
/// **Example:**
179+
/// ```rust
180+
/// // u32 is 32-bit aligned; u8 is 8-bit aligned
181+
/// let _: u32 = unsafe { std::mem::transmute([0u8; 4]) };
182+
/// ```
183+
declare_lint! {
184+
pub MISALIGNED_TRANSMUTE,
185+
Warn,
186+
"transmutes to a potentially less-aligned type"
187+
}
188+
171189
pub struct Transmute;
172190

173191
impl LintPass for Transmute {
@@ -180,7 +198,8 @@ impl LintPass for Transmute {
180198
TRANSMUTE_INT_TO_CHAR,
181199
TRANSMUTE_BYTES_TO_STR,
182200
TRANSMUTE_INT_TO_BOOL,
183-
TRANSMUTE_INT_TO_FLOAT
201+
TRANSMUTE_INT_TO_FLOAT,
202+
MISALIGNED_TRANSMUTE
184203
)
185204
}
186205
}
@@ -201,6 +220,18 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Transmute {
201220
e.span,
202221
&format!("transmute from a type (`{}`) to itself", from_ty),
203222
),
223+
_ if alignment(cx, from_ty).map(|a| a.abi())
224+
< alignment(cx, to_ty).map(|a| a.abi())
225+
=> span_lint(
226+
cx,
227+
MISALIGNED_TRANSMUTE,
228+
e.span,
229+
&format!(
230+
"transmute from `{}` to a less-aligned type (`{}`)",
231+
from_ty,
232+
to_ty,
233+
)
234+
),
204235
(&ty::TyRef(_, rty), &ty::TyRawPtr(ptr_ty)) => span_lint_and_then(
205236
cx,
206237
USELESS_TRANSMUTE,

clippy_lints/src/utils/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc::lint::{LateContext, Level, Lint, LintContext};
99
use rustc::session::Session;
1010
use rustc::traits;
1111
use rustc::ty::{self, Ty, TyCtxt};
12-
use rustc::ty::layout::LayoutOf;
12+
use rustc::ty::layout::{LayoutOf, Align};
1313
use rustc_errors;
1414
use std::borrow::Cow;
1515
use std::env;
@@ -1056,3 +1056,8 @@ pub fn get_arg_name(pat: &Pat) -> Option<ast::Name> {
10561056
_ => None,
10571057
}
10581058
}
1059+
1060+
/// Returns alignment for a type, or None if alignment is undefined
1061+
pub fn alignment<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Option<Align> {
1062+
(cx.tcx, cx.param_env).layout_of(ty).ok().map(|layout| layout.align)
1063+
}

tests/ui/transmute.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,11 @@ fn bytes_to_str(b: &[u8], mb: &mut [u8]) {
140140
let _: &mut str = unsafe { std::mem::transmute(mb) };
141141
}
142142

143+
#[warn(misaligned_transmute)]
144+
fn misaligned_transmute() {
145+
let _: u32 = unsafe { std::mem::transmute([0u8; 4]) }; // err
146+
let _: u32 = unsafe { std::mem::transmute(0f32) }; // ok (alignment-wise)
147+
let _: [u8; 4] = unsafe { std::mem::transmute(0u32) }; // ok (alignment-wise)
148+
}
149+
143150
fn main() { }

tests/ui/transmute.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,5 +204,13 @@ error: transmute from a `&mut [u8]` to a `&mut str`
204204
140 | let _: &mut str = unsafe { std::mem::transmute(mb) };
205205
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
206206

207-
error: aborting due to 32 previous errors
207+
error: transmute from `[u8; 4]` to a less-aligned type (`u32`)
208+
--> $DIR/transmute.rs:145:27
209+
|
210+
145 | let _: u32 = unsafe { std::mem::transmute([0u8; 4]) }; // err
211+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
212+
|
213+
= note: `-D misaligned-transmute` implied by `-D warnings`
214+
215+
error: aborting due to 33 previous errors
208216

0 commit comments

Comments
 (0)