Merge pull request #2096 from lpesk/invalid-ref

Lint for creation of invalid references
This commit is contained in:
Oliver Schneider 2017-09-30 16:19:12 +02:00 committed by GitHub
commit 1cf4672b49
5 changed files with 179 additions and 0 deletions

View file

@ -0,0 +1,55 @@
use rustc::lint::*;
use rustc::ty;
use rustc::hir::*;
use utils::{match_def_path, paths, span_help_and_lint, opt_def_id};
/// **What it does:** Checks for creation of references to zeroed or uninitialized memory.
///
/// **Why is this bad?** Creation of null references is undefined behavior.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// let bad_ref: &usize = std::mem::zeroed();
/// ```
declare_lint! {
pub INVALID_REF,
Warn,
"creation of invalid reference"
}
const ZERO_REF_SUMMARY: &str = "reference to zeroed memory";
const UNINIT_REF_SUMMARY: &str = "reference to uninitialized memory";
const HELP: &str = "Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html";
pub struct InvalidRef;
impl LintPass for InvalidRef {
fn get_lints(&self) -> LintArray {
lint_array!(INVALID_REF)
}
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidRef {
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
if_let_chain!{[
let ExprCall(ref path, ref args) = expr.node,
let ExprPath(ref qpath) = path.node,
args.len() == 0,
let ty::TyRef(..) = cx.tables.expr_ty(expr).sty,
let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path.hir_id)),
], {
let msg = if match_def_path(cx.tcx, def_id, &paths::MEM_ZEROED) | match_def_path(cx.tcx, def_id, &paths::INIT) {
ZERO_REF_SUMMARY
} else if match_def_path(cx.tcx, def_id, &paths::MEM_UNINIT) | match_def_path(cx.tcx, def_id, &paths::UNINIT) {
UNINIT_REF_SUMMARY
} else {
return;
};
span_help_and_lint(cx, INVALID_REF, expr.span, msg, HELP);
}}
return;
}
}

View file

@ -97,6 +97,7 @@ pub mod if_let_redundant_pattern_matching;
pub mod if_not_else;
pub mod infinite_iter;
pub mod int_plus_one;
pub mod invalid_ref;
pub mod is_unit_expr;
pub mod items_after_statements;
pub mod large_enum_variant;
@ -328,6 +329,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
reg.register_late_lint_pass(box use_self::UseSelf);
reg.register_late_lint_pass(box bytecount::ByteCount);
reg.register_late_lint_pass(box infinite_iter::Pass);
reg.register_late_lint_pass(box invalid_ref::InvalidRef);
reg.register_lint_group("clippy_restrictions", vec![
arithmetic::FLOAT_ARITHMETIC,
@ -345,6 +347,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
if_not_else::IF_NOT_ELSE,
infinite_iter::MAYBE_INFINITE_ITER,
int_plus_one::INT_PLUS_ONE,
invalid_ref::INVALID_REF,
items_after_statements::ITEMS_AFTER_STATEMENTS,
matches::SINGLE_MATCH_ELSE,
mem_forget::MEM_FORGET,

View file

@ -30,6 +30,7 @@ pub const HASH: [&'static str; 2] = ["hash", "Hash"];
pub const HASHMAP: [&'static str; 5] = ["std", "collections", "hash", "map", "HashMap"];
pub const HASHMAP_ENTRY: [&'static str; 5] = ["std", "collections", "hash", "map", "Entry"];
pub const HASHSET: [&'static str; 5] = ["std", "collections", "hash", "set", "HashSet"];
pub const INIT: [&'static str; 4] = ["core", "intrinsics", "", "init"];
pub const INTO_ITERATOR: [&'static str; 4] = ["core", "iter", "traits", "IntoIterator"];
pub const IO_PRINT: [&'static str; 4] = ["std", "io", "stdio", "_print"];
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"
pub const LINT: [&'static str; 3] = ["rustc", "lint", "Lint"];
pub const LINT_ARRAY: [&'static str; 3] = ["rustc", "lint", "LintArray"];
pub const MEM_FORGET: [&'static str; 3] = ["core", "mem", "forget"];
pub const MEM_UNINIT: [&'static str; 3] = ["core", "mem", "uninitialized"];
pub const MEM_ZEROED: [&'static str; 3] = ["core", "mem", "zeroed"];
pub const MUTEX: [&'static str; 4] = ["std", "sync", "mutex", "Mutex"];
pub const OPEN_OPTIONS: [&'static str; 3] = ["std", "fs", "OpenOptions"];
pub const OPS_MODULE: [&'static str; 2] = ["core", "ops"];
@ -80,6 +83,7 @@ pub const TO_OWNED: [&'static str; 3] = ["alloc", "borrow", "ToOwned"];
pub const TO_STRING: [&'static str; 3] = ["alloc", "string", "ToString"];
pub const TRANSMUTE: [&'static str; 4] = ["core", "intrinsics", "", "transmute"];
pub const TRY_INTO_RESULT: [&'static str; 4] = ["std", "ops", "Try", "into_result"];
pub const UNINIT: [&'static str; 4] = ["core", "intrinsics", "", "uninit"];
pub const VEC: [&'static str; 3] = ["alloc", "vec", "Vec"];
pub const VEC_DEQUE: [&'static str; 3] = ["alloc", "vec_deque", "VecDeque"];
pub const VEC_FROM_ELEM: [&'static str; 3] = ["alloc", "vec", "from_elem"];

66
tests/ui/invalid_ref.rs Normal file
View file

@ -0,0 +1,66 @@
#![feature(plugin)]
#![plugin(clippy)]
#![allow(unused)]
#![feature(core_intrinsics)]
extern crate core;
use std::intrinsics::{init, uninit};
fn main() {
let x = 1;
unsafe {
ref_to_zeroed_std(&x);
ref_to_zeroed_core(&x);
ref_to_zeroed_intr(&x);
ref_to_uninit_std(&x);
ref_to_uninit_core(&x);
ref_to_uninit_intr(&x);
some_ref();
std_zeroed_no_ref();
core_zeroed_no_ref();
intr_init_no_ref();
}
}
unsafe fn ref_to_zeroed_std<T: ?Sized>(t: &T) {
let ref_zero: &T = std::mem::zeroed(); // warning
}
unsafe fn ref_to_zeroed_core<T: ?Sized>(t: &T) {
let ref_zero: &T = core::mem::zeroed(); // warning
}
unsafe fn ref_to_zeroed_intr<T: ?Sized>(t: &T) {
let ref_zero: &T = std::intrinsics::init(); // warning
}
unsafe fn ref_to_uninit_std<T: ?Sized>(t: &T) {
let ref_uninit: &T = std::mem::uninitialized(); // warning
}
unsafe fn ref_to_uninit_core<T: ?Sized>(t: &T) {
let ref_uninit: &T = core::mem::uninitialized(); // warning
}
unsafe fn ref_to_uninit_intr<T: ?Sized>(t: &T) {
let ref_uninit: &T = std::intrinsics::uninit(); // warning
}
fn some_ref() {
let some_ref = &1;
}
unsafe fn std_zeroed_no_ref() {
let mem_zero: usize = std::mem::zeroed(); // no warning
}
unsafe fn core_zeroed_no_ref() {
let mem_zero: usize = core::mem::zeroed(); // no warning
}
unsafe fn intr_init_no_ref() {
let mem_zero: usize = std::intrinsics::init(); // no warning
}

View file

@ -0,0 +1,51 @@
error: reference to zeroed memory
--> $DIR/invalid_ref.rs:27:24
|
27 | let ref_zero: &T = std::mem::zeroed(); // warning
| ^^^^^^^^^^^^^^^^^^
|
= note: `-D invalid-ref` implied by `-D warnings`
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: reference to zeroed memory
--> $DIR/invalid_ref.rs:31:24
|
31 | let ref_zero: &T = core::mem::zeroed(); // warning
| ^^^^^^^^^^^^^^^^^^^
|
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: reference to zeroed memory
--> $DIR/invalid_ref.rs:35:24
|
35 | let ref_zero: &T = std::intrinsics::init(); // warning
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: reference to uninitialized memory
--> $DIR/invalid_ref.rs:39:26
|
39 | let ref_uninit: &T = std::mem::uninitialized(); // warning
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: reference to uninitialized memory
--> $DIR/invalid_ref.rs:43:26
|
43 | let ref_uninit: &T = core::mem::uninitialized(); // warning
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: reference to uninitialized memory
--> $DIR/invalid_ref.rs:47:26
|
47 | let ref_uninit: &T = std::intrinsics::uninit(); // warning
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: Creation of a null reference is undefined behavior; see https://doc.rust-lang.org/reference/behavior-considered-undefined.html
error: aborting due to 6 previous errors