mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-03 12:13:43 +00:00
add basic lint testing for misuse of mem::zeroed and mem::uninitialized
This commit is contained in:
parent
6f70adcb18
commit
da6fbb1895
@ -1862,3 +1862,62 @@ impl EarlyLintPass for IncompleteFeatures {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub INVALID_VALUE,
|
||||
Warn,
|
||||
"an invalid value is being created (such as a NULL reference)"
|
||||
}
|
||||
|
||||
declare_lint_pass!(InvalidValue => [INVALID_VALUE]);
|
||||
|
||||
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
|
||||
fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &hir::Expr) {
|
||||
|
||||
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
|
||||
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
|
||||
|
||||
/// Return `false` only if we are sure this type does *not*
|
||||
/// allow zero initialization.
|
||||
fn ty_maybe_allows_zero_init(ty: Ty<'_>) -> bool {
|
||||
use rustc::ty::TyKind::*;
|
||||
match ty.sty {
|
||||
// Primitive types that don't like 0 as a value.
|
||||
Ref(..) | FnPtr(..) | Never => false,
|
||||
// Conservative fallback.
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
|
||||
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
|
||||
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
|
||||
if cx.match_def_path(def_id, &ZEROED_PATH) ||
|
||||
cx.match_def_path(def_id, &UININIT_PATH)
|
||||
{
|
||||
// This conjures an instance of a type out of nothing,
|
||||
// using zeroed or uninitialized memory.
|
||||
// We are extremely conservative with what we warn about.
|
||||
let conjured_ty = cx.tables.expr_ty(expr);
|
||||
|
||||
if !ty_maybe_allows_zero_init(conjured_ty) {
|
||||
cx.span_lint(
|
||||
INVALID_VALUE,
|
||||
expr.span,
|
||||
&format!(
|
||||
"the type `{}` does not permit {}",
|
||||
conjured_ty,
|
||||
if cx.match_def_path(def_id, &ZEROED_PATH) {
|
||||
"zero-initialization"
|
||||
} else {
|
||||
"being left uninitialized"
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,7 @@ macro_rules! late_lint_mod_passes {
|
||||
UnreachablePub: UnreachablePub,
|
||||
|
||||
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
|
||||
InvalidValue: InvalidValue,
|
||||
]);
|
||||
)
|
||||
}
|
||||
|
@ -412,6 +412,7 @@ symbols! {
|
||||
match_beginning_vert,
|
||||
match_default_bindings,
|
||||
may_dangle,
|
||||
mem,
|
||||
member_constraints,
|
||||
message,
|
||||
meta,
|
||||
@ -695,6 +696,7 @@ symbols! {
|
||||
underscore_imports,
|
||||
underscore_lifetimes,
|
||||
uniform_paths,
|
||||
uninitialized,
|
||||
universal_impl_trait,
|
||||
unmarked_api,
|
||||
unreachable_code,
|
||||
@ -726,6 +728,7 @@ symbols! {
|
||||
windows,
|
||||
windows_subsystem,
|
||||
Yield,
|
||||
zeroed,
|
||||
}
|
||||
}
|
||||
|
||||
|
28
src/test/ui/lint/uninitialized-zeroed.rs
Normal file
28
src/test/ui/lint/uninitialized-zeroed.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// ignore-tidy-linelength
|
||||
// This test checks that calling `mem::{uninitialized,zeroed}` with certain types results
|
||||
// in a lint.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(deprecated)]
|
||||
#![deny(invalid_value)]
|
||||
|
||||
use std::mem;
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
let _val: ! = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: ! = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
let _val: &'static i32 = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: &'static i32 = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
let _val: fn() = mem::zeroed(); //~ ERROR: does not permit zero-initialization
|
||||
let _val: fn() = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
|
||||
|
||||
// Some types that should work just fine.
|
||||
let _val: Option<&'static i32> = mem::zeroed();
|
||||
let _val: Option<fn()> = mem::zeroed();
|
||||
let _val: bool = mem::zeroed();
|
||||
let _val: i32 = mem::zeroed();
|
||||
}
|
||||
}
|
44
src/test/ui/lint/uninitialized-zeroed.stderr
Normal file
44
src/test/ui/lint/uninitialized-zeroed.stderr
Normal file
@ -0,0 +1,44 @@
|
||||
error: the type `!` does not permit zero-initialization
|
||||
--> $DIR/uninitialized-zeroed.rs:15:23
|
||||
|
|
||||
LL | let _val: ! = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
note: lint level defined here
|
||||
--> $DIR/uninitialized-zeroed.rs:7:9
|
||||
|
|
||||
LL | #![deny(invalid_value)]
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: the type `!` does not permit being left uninitialized
|
||||
--> $DIR/uninitialized-zeroed.rs:16:23
|
||||
|
|
||||
LL | let _val: ! = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: the type `&'static i32` does not permit zero-initialization
|
||||
--> $DIR/uninitialized-zeroed.rs:21:34
|
||||
|
|
||||
LL | let _val: &'static i32 = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: the type `&'static i32` does not permit being left uninitialized
|
||||
--> $DIR/uninitialized-zeroed.rs:22:34
|
||||
|
|
||||
LL | let _val: &'static i32 = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: the type `fn()` does not permit zero-initialization
|
||||
--> $DIR/uninitialized-zeroed.rs:24:26
|
||||
|
|
||||
LL | let _val: fn() = mem::zeroed();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: the type `fn()` does not permit being left uninitialized
|
||||
--> $DIR/uninitialized-zeroed.rs:25:26
|
||||
|
|
||||
LL | let _val: fn() = mem::uninitialized();
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
@ -4,7 +4,7 @@
|
||||
// in a runtime panic.
|
||||
|
||||
#![feature(never_type)]
|
||||
#![allow(deprecated)]
|
||||
#![allow(deprecated, invalid_value)]
|
||||
|
||||
use std::{mem, panic};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user