Skip to content

Commit d0f3360

Browse files
committed
lint: deny transmuting from immutable to mutable, since it's undefined behavior
1 parent acb3e51 commit d0f3360

File tree

3 files changed

+97
-0
lines changed

3 files changed

+97
-0
lines changed

src/librustc_lint/builtin.rs

+76
Original file line numberDiff line numberDiff line change
@@ -2087,6 +2087,82 @@ impl LintPass for InvalidNoMangleItems {
20872087
}
20882088
}
20892089

2090+
#[derive(Clone, Copy)]
2091+
pub struct MutableTransmutes;
2092+
2093+
declare_lint! {
2094+
MUTABLE_TRANSMUTES,
2095+
Deny,
2096+
"transmuting from &T to &mut T is undefined behavior"
2097+
}
2098+
2099+
impl LintPass for MutableTransmutes {
2100+
fn get_lints(&self) -> LintArray {
2101+
lint_array!(MUTABLE_TRANSMUTES)
2102+
}
2103+
2104+
fn check_expr(&mut self, cx: &Context, expr: &ast::Expr) {
2105+
use syntax::ast::DefId;
2106+
use syntax::abi::RustIntrinsic;
2107+
let msg = "transmuting from immutable to mutable is undefined behavior";
2108+
match get_transmute_from_to(cx, expr) {
2109+
Some((&ty::ty_rptr(_, from_mt), &ty::ty_rptr(_, to_mt))) => {
2110+
if to_mt.mutbl == ast::Mutability::MutMutable
2111+
&& from_mt.mutbl == ast::Mutability::MutImmutable {
2112+
cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
2113+
}
2114+
}
2115+
_ => ()
2116+
}
2117+
2118+
fn get_transmute_from_to<'a, 'tcx>(cx: &Context<'a, 'tcx>, expr: &ast::Expr)
2119+
-> Option<(&'tcx ty::sty<'tcx>, &'tcx ty::sty<'tcx>)> {
2120+
if let ast::ExprPath(..) = expr.node {
2121+
if let DefFn(did, _) = ty::resolve_expr(cx.tcx, expr) {
2122+
if def_id_is_transmute(cx, did) {
2123+
let typ = ty::node_id_to_type(cx.tcx, expr.id);
2124+
match typ.sty {
2125+
ty::ty_bare_fn(_, ref bare_fn) if bare_fn.abi == RustIntrinsic => {
2126+
if let ty::FnConverging(to) = bare_fn.sig.0.output {
2127+
let from = bare_fn.sig.0.inputs[0];
2128+
return Some((&from.sty, &to.sty));
2129+
}
2130+
},
2131+
_ => ()
2132+
}
2133+
}
2134+
}
2135+
}
2136+
None
2137+
}
2138+
2139+
fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool {
2140+
use syntax::ast_map::NodeForeignItem;
2141+
let intrinsic = match ty::lookup_item_type(cx.tcx, def_id).ty.sty {
2142+
ty::ty_bare_fn(_, ref bfty) => bfty.abi == RustIntrinsic,
2143+
_ => return false
2144+
};
2145+
if def_id.krate == ast::LOCAL_CRATE {
2146+
match cx.tcx.map.get(def_id.node) {
2147+
NodeForeignItem(ref item) if intrinsic => {
2148+
token::get_ident(item.ident) ==
2149+
token::intern_and_get_ident("transmute")
2150+
}
2151+
_ => false,
2152+
}
2153+
} else {
2154+
match csearch::get_item_path(cx.tcx, def_id).last() {
2155+
Some(ref last) if intrinsic => {
2156+
token::get_name(last.name()) ==
2157+
token::intern_and_get_ident("transmute")
2158+
}
2159+
_ => false,
2160+
}
2161+
}
2162+
}
2163+
}
2164+
}
2165+
20902166
/// Forbids using the `#[feature(...)]` attribute
20912167
#[derive(Copy, Clone)]
20922168
pub struct UnstableFeatures;

src/librustc_lint/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
109109
UnconditionalRecursion,
110110
InvalidNoMangleItems,
111111
PluginAsLibrary,
112+
MutableTransmutes,
112113
);
113114

114115
add_builtin_with_new!(sess,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Tests that transmuting from &T to &mut T is Undefined Behavior.
12+
13+
use std::mem::transmute;
14+
15+
fn main() {
16+
let _a: &mut u8 = unsafe { transmute(&1u8) };
17+
//~^ ERROR transmuting from immutable to mutable is undefined behavior
18+
}
19+
20+

0 commit comments

Comments
 (0)