Merge pull request #2096 from lpesk/invalid-ref
Lint for creation of invalid references
This commit is contained in:
commit
1cf4672b49
5 changed files with 179 additions and 0 deletions
55
clippy_lints/src/invalid_ref.rs
Normal file
55
clippy_lints/src/invalid_ref.rs
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
66
tests/ui/invalid_ref.rs
Normal 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
|
||||
}
|
||||
|
||||
|
||||
51
tests/ui/invalid_ref.stderr
Normal file
51
tests/ui/invalid_ref.stderr
Normal 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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue