Skip to content

Commit 1cf4672

Browse files
authored
Merge pull request #2096 from lpesk/invalid-ref
Lint for creation of invalid references
2 parents 06280e8 + 8e6abc6 commit 1cf4672

File tree

5 files changed

+179
-0
lines changed

5 files changed

+179
-0
lines changed

clippy_lints/src/invalid_ref.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use rustc::lint::*;
2+
use rustc::ty;
3+
use rustc::hir::*;
4+
use utils::{match_def_path, paths, span_help_and_lint, opt_def_id};
5+
6+
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
7+
///
8+
/// **Why is this bad?** Creation of null references is undefined behavior.
9+
///
10+
/// **Known problems:** None.
11+
///
12+
/// **Example:**
13+
/// ```rust
14+
/// let bad_ref: &usize = std::mem::zeroed();
15+
/// ```
16+
17+
declare_lint! {
18+
pub INVALID_REF,
19+
Warn,
20+
"creation of invalid reference"
21+
}
22+
23+
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
24+
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory";
25+
const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
26+
27+
pub struct InvalidRef;
28+
29+
impl LintPass for InvalidRef {
30+
fn get_lints(&self) -> LintArray {
31+
lint_array!(INVALID_REF)
32+
}
33+
}
34+
35+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
36+
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
37+
if_let_chain!{[
38+
let ExprCall(ref path, ref args) = expr.node,
39+
let ExprPath(ref qpath) = path.node,
40+
args.len() == 0,
41+
let ty::TyRef(..) = cx.tables.expr_ty(expr).sty,
42+
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)),
43+
], {
44+
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
45+
ZERO_REF_SUMMARY
46+
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
47+
UNINIT_REF_SUMMARY
48+
} else {
49+
return;
50+
};
51+
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
52+
}}
53+
return;
54+
}
55+
}

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ pub mod if_let_redundant_pattern_matching;
9797
pub mod if_not_else;
9898
pub mod infinite_iter;
9999
pub mod int_plus_one;
100+
pub mod invalid_ref;
100101
pub mod is_unit_expr;
101102
pub mod items_after_statements;
102103
pub mod large_enum_variant;
@@ -328,6 +329,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
328329
reg.register_late_lint_pass(box use_self::UseSelf);
329330
reg.register_late_lint_pass(box bytecount::ByteCount);
330331
reg.register_late_lint_pass(box infinite_iter::Pass);
332+
reg.register_late_lint_pass(box invalid_ref::InvalidRef);
331333

332334
reg.register_lint_group("clippy_restrictions", vec![
333335
arithmetic::FLOAT_ARITHMETIC,
@@ -345,6 +347,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
345347
if_not_else::IF_NOT_ELSE,
346348
infinite_iter::MAYBE_INFINITE_ITER,
347349
int_plus_one::INT_PLUS_ONE,
350+
invalid_ref::INVALID_REF,
348351
items_after_statements::ITEMS_AFTER_STATEMENTS,
349352
matches::SINGLE_MATCH_ELSE,
350353
mem_forget::MEM_FORGET,

clippy_lints/src/utils/paths.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub const HASH: [&'static str; 2] = ["hash", "Hash"];
3030
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
3131
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
3232
pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"];
33+
pub const INIT: [&'static str; 4] = ["core", "intrinsics", "", "init"];
3334
pub const INTO_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", "IntoIterator"];
3435
pub const IO_PRINT: [&'static str; 4] = ["std", "io", "stdio", "_print"];
3536
pub const IO_READ: [&'static str; 3] = ["std", "io", "Read"];
@@ -39,6 +40,8 @@ pub const LINKED_LIST: [&'static str; 3] = ["alloc", "linked_list", "LinkedList"
3940
pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"];
4041
pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"];
4142
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
43+
pub const MEM_UNINIT: [&'static str; 3] = ["core", "mem", "uninitialized"];
44+
pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"];
4245
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
4346
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
4447
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
@@ -80,6 +83,7 @@ pub const TO_OWNED: [&'static str; 3] = ["alloc", "borrow", "ToOwned"];
8083
pub const TO_STRING: [&'static str; 3] = ["alloc", "string", "ToString"];
8184
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
8285
pub const TRY_INTO_RESULT: [&'static str; 4] = ["std", "ops", "Try", "into_result"];
86+
pub const UNINIT: [&'static str; 4] = ["core", "intrinsics", "", "uninit"];
8387
pub const VEC: [&'static str; 3] = ["alloc", "vec", "Vec"];
8488
pub const VEC_DEQUE: [&'static str; 3] = ["alloc", "vec_deque", "VecDeque"];
8589
pub const VEC_FROM_ELEM: [&'static str; 3] = ["alloc", "vec", "from_elem"];

tests/ui/invalid_ref.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#![feature(plugin)]
2+
#![plugin(clippy)]
3+
4+
#![allow(unused)]
5+
#![feature(core_intrinsics)]
6+
7+
extern crate core;
8+
use std::intrinsics::{init, uninit};
9+
10+
fn main() {
11+
let x = 1;
12+
unsafe {
13+
ref_to_zeroed_std(&x);
14+
ref_to_zeroed_core(&x);
15+
ref_to_zeroed_intr(&x);
16+
ref_to_uninit_std(&x);
17+
ref_to_uninit_core(&x);
18+
ref_to_uninit_intr(&x);
19+
some_ref();
20+
std_zeroed_no_ref();
21+
core_zeroed_no_ref();
22+
intr_init_no_ref();
23+
}
24+
}
25+
26+
unsafe fn ref_to_zeroed_std<T: ?Sized>(t: &T) {
27+
let ref_zero: &T = std::mem::zeroed(); // warning
28+
}
29+
30+
unsafe fn ref_to_zeroed_core<T: ?Sized>(t: &T) {
31+
let ref_zero: &T = core::mem::zeroed(); // warning
32+
}
33+
34+
unsafe fn ref_to_zeroed_intr<T: ?Sized>(t: &T) {
35+
let ref_zero: &T = std::intrinsics::init(); // warning
36+
}
37+
38+
unsafe fn ref_to_uninit_std<T: ?Sized>(t: &T) {
39+
let ref_uninit: &T = std::mem::uninitialized(); // warning
40+
}
41+
42+
unsafe fn ref_to_uninit_core<T: ?Sized>(t: &T) {
43+
let ref_uninit: &T = core::mem::uninitialized(); // warning
44+
}
45+
46+
unsafe fn ref_to_uninit_intr<T: ?Sized>(t: &T) {
47+
let ref_uninit: &T = std::intrinsics::uninit(); // warning
48+
}
49+
50+
fn some_ref() {
51+
let some_ref = &1;
52+
}
53+
54+
unsafe fn std_zeroed_no_ref() {
55+
let mem_zero: usize = std::mem::zeroed(); // no warning
56+
}
57+
58+
unsafe fn core_zeroed_no_ref() {
59+
let mem_zero: usize = core::mem::zeroed(); // no warning
60+
}
61+
62+
unsafe fn intr_init_no_ref() {
63+
let mem_zero: usize = std::intrinsics::init(); // no warning
64+
}
65+
66+

tests/ui/invalid_ref.stderr

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
error: reference to zeroed memory
2+
--> $DIR/invalid_ref.rs:27:24
3+
|
4+
27 | let ref_zero: &T = std::mem::zeroed(); // warning
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D invalid-ref` implied by `-D warnings`
8+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
9+
10+
error: reference to zeroed memory
11+
--> $DIR/invalid_ref.rs:31:24
12+
|
13+
31 | let ref_zero: &T = core::mem::zeroed(); // warning
14+
| ^^^^^^^^^^^^^^^^^^^
15+
|
16+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
17+
18+
error: reference to zeroed memory
19+
--> $DIR/invalid_ref.rs:35:24
20+
|
21+
35 | let ref_zero: &T = std::intrinsics::init(); // warning
22+
| ^^^^^^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
25+
26+
error: reference to uninitialized memory
27+
--> $DIR/invalid_ref.rs:39:26
28+
|
29+
39 | let ref_uninit: &T = std::mem::uninitialized(); // warning
30+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
31+
|
32+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
33+
34+
error: reference to uninitialized memory
35+
--> $DIR/invalid_ref.rs:43:26
36+
|
37+
43 | let ref_uninit: &T = core::mem::uninitialized(); // warning
38+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
39+
|
40+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
41+
42+
error: reference to uninitialized memory
43+
--> $DIR/invalid_ref.rs:47:26
44+
|
45+
47 | let ref_uninit: &T = std::intrinsics::uninit(); // warning
46+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
47+
|
48+
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
49+
50+
error: aborting due to 6 previous errors
51+

0 commit comments

Comments
 (0)