Auto merge of #10520 - Nilstrieb:uninit, r=Alexendoo
Use uninit checking from rustc rustc has proper heuristics for actually checking whether a type allows being left uninitialized (by asking CTFE). We can now use this for our helper instead of rolling our own bad version with false positives. I added this in rustc in rust-lang/rust#108669 Fix #10407 changelog: [`uninit_vec`]: fix false positives changelog: [`uninit_assumed_init`]: fix false positives
This commit is contained in:
commit
7b3c4aa771
@ -16,9 +16,9 @@
|
||||
use rustc_lint::LateContext;
|
||||
use rustc_middle::mir::interpret::{ConstValue, Scalar};
|
||||
use rustc_middle::ty::{
|
||||
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
|
||||
Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
|
||||
UintTy, VariantDef, VariantDiscr,
|
||||
self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
|
||||
Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
|
||||
};
|
||||
use rustc_middle::ty::{GenericArg, GenericArgKind};
|
||||
use rustc_span::symbol::Ident;
|
||||
@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
|
||||
}
|
||||
|
||||
/// Checks if a given type looks safe to be uninitialized.
|
||||
pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
|
||||
match *ty.kind() {
|
||||
ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
|
||||
ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
|
||||
ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()),
|
||||
_ => false,
|
||||
}
|
||||
pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
cx.tcx
|
||||
.check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty)))
|
||||
// For types containing generic parameters we cannot get a layout to check.
|
||||
// Therefore, we are conservative and assume that they don't allow uninit.
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Gets an iterator over all predicates which apply to the given item.
|
||||
|
@ -3,13 +3,15 @@
|
||||
|
||||
use std::mem::{self, MaybeUninit};
|
||||
|
||||
union MyOwnMaybeUninit {
|
||||
value: u8,
|
||||
uninit: (),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// edge case: For now we lint on empty arrays
|
||||
let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// edge case: For now we accept unit tuples
|
||||
// This is OK, because ZSTs do not contain data.
|
||||
let _: () = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// This is OK, because `MaybeUninit` allows uninitialized data.
|
||||
@ -21,6 +23,19 @@ fn main() {
|
||||
// This is OK, because all constitutent types are uninit-compatible.
|
||||
let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// This is OK, because our own MaybeUninit is just as fine as the one from core.
|
||||
let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// This is OK, because empty arrays don't contain data.
|
||||
let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
|
||||
// Was a false negative.
|
||||
let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
|
||||
|
||||
polymorphic::<()>();
|
||||
|
||||
fn polymorphic<T>() {
|
||||
// We are conservative around polymorphic types.
|
||||
let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: this call for this type may be undefined behavior
|
||||
--> $DIR/uninit.rs:7:29
|
||||
--> $DIR/uninit.rs:12:29
|
||||
|
|
||||
LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -7,16 +7,16 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
= note: `#[deny(clippy::uninit_assumed_init)]` on by default
|
||||
|
||||
error: this call for this type may be undefined behavior
|
||||
--> $DIR/uninit.rs:10:31
|
||||
|
|
||||
LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this call for this type may be undefined behavior
|
||||
--> $DIR/uninit.rs:25:29
|
||||
--> $DIR/uninit.rs:33:29
|
||||
|
|
||||
LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: this call for this type may be undefined behavior
|
||||
--> $DIR/uninit.rs:39:29
|
||||
|
|
||||
LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
@ -7,6 +7,11 @@ struct MyVec {
|
||||
vec: Vec<u8>,
|
||||
}
|
||||
|
||||
union MyOwnMaybeUninit {
|
||||
value: u8,
|
||||
uninit: (),
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// with_capacity() -> set_len() should be detected
|
||||
let mut vec: Vec<u8> = Vec::with_capacity(1000);
|
||||
@ -97,4 +102,26 @@ fn main() {
|
||||
unsafe {
|
||||
vec.set_len(0);
|
||||
}
|
||||
|
||||
// ZSTs should not be detected
|
||||
let mut vec: Vec<()> = Vec::with_capacity(1000);
|
||||
unsafe {
|
||||
vec.set_len(10);
|
||||
}
|
||||
|
||||
// unions should not be detected
|
||||
let mut vec: Vec<MyOwnMaybeUninit> = Vec::with_capacity(1000);
|
||||
unsafe {
|
||||
vec.set_len(10);
|
||||
}
|
||||
|
||||
polymorphic::<()>();
|
||||
|
||||
fn polymorphic<T>() {
|
||||
// We are conservative around polymorphic types.
|
||||
let mut vec: Vec<T> = Vec::with_capacity(1000);
|
||||
unsafe {
|
||||
vec.set_len(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:12:5
|
||||
--> $DIR/uninit_vec.rs:17:5
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -11,7 +11,7 @@ LL | vec.set_len(200);
|
||||
= note: `-D clippy::uninit-vec` implied by `-D warnings`
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:18:5
|
||||
--> $DIR/uninit_vec.rs:23:5
|
||||
|
|
||||
LL | vec.reserve(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -22,7 +22,7 @@ LL | vec.set_len(200);
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: calling `set_len()` on empty `Vec` creates out-of-bound values
|
||||
--> $DIR/uninit_vec.rs:24:5
|
||||
--> $DIR/uninit_vec.rs:29:5
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Vec::new();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -31,7 +31,7 @@ LL | vec.set_len(200);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: calling `set_len()` on empty `Vec` creates out-of-bound values
|
||||
--> $DIR/uninit_vec.rs:30:5
|
||||
--> $DIR/uninit_vec.rs:35:5
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Default::default();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -40,7 +40,7 @@ LL | vec.set_len(200);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: calling `set_len()` on empty `Vec` creates out-of-bound values
|
||||
--> $DIR/uninit_vec.rs:35:5
|
||||
--> $DIR/uninit_vec.rs:40:5
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Vec::default();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -49,7 +49,7 @@ LL | vec.set_len(200);
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:49:5
|
||||
--> $DIR/uninit_vec.rs:54:5
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -60,7 +60,7 @@ LL | vec.set_len(200);
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:58:5
|
||||
--> $DIR/uninit_vec.rs:63:5
|
||||
|
|
||||
LL | my_vec.vec.reserve(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -71,7 +71,7 @@ LL | my_vec.vec.set_len(200);
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:63:5
|
||||
--> $DIR/uninit_vec.rs:68:5
|
||||
|
|
||||
LL | my_vec.vec = Vec::with_capacity(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -82,7 +82,7 @@ LL | my_vec.vec.set_len(200);
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:42:9
|
||||
--> $DIR/uninit_vec.rs:47:9
|
||||
|
|
||||
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
@ -92,7 +92,7 @@ LL | vec.set_len(200);
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:45:9
|
||||
--> $DIR/uninit_vec.rs:50:9
|
||||
|
|
||||
LL | vec.reserve(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
@ -101,5 +101,16 @@ LL | vec.set_len(200);
|
||||
|
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: aborting due to 10 previous errors
|
||||
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
|
||||
--> $DIR/uninit_vec.rs:122:9
|
||||
|
|
||||
LL | let mut vec: Vec<T> = Vec::with_capacity(1000);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | unsafe {
|
||||
LL | vec.set_len(10);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: initialize the buffer or wrap the content in `MaybeUninit`
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user