Skip to content

Commit 7b3c4aa

Browse files
committed
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
2 parents 0a77f4c + 84b6049 commit 7b3c4aa

File tree

5 files changed

+83
-31
lines changed

5 files changed

+83
-31
lines changed

clippy_utils/src/ty.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use rustc_infer::infer::{
1616
use rustc_lint::LateContext;
1717
use rustc_middle::mir::interpret::{ConstValue, Scalar};
1818
use rustc_middle::ty::{
19-
self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv, Predicate, PredicateKind,
20-
Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
21-
UintTy, VariantDef, VariantDiscr,
19+
self, layout::ValidityRequirement, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, IntTy, List, ParamEnv,
20+
Predicate, PredicateKind, Region, RegionKind, SubstsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
21+
TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
2222
};
2323
use rustc_middle::ty::{GenericArg, GenericArgKind};
2424
use rustc_span::symbol::Ident;
@@ -538,13 +538,12 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
538538
}
539539

540540
/// Checks if a given type looks safe to be uninitialized.
541-
pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
542-
match *ty.kind() {
543-
ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
544-
ty::Tuple(types) => types.iter().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
545-
ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did()),
546-
_ => false,
547-
}
541+
pub fn is_uninit_value_valid_for_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
542+
cx.tcx
543+
.check_validity_requirement((ValidityRequirement::Uninit, cx.param_env.and(ty)))
544+
// For types containing generic parameters we cannot get a layout to check.
545+
// Therefore, we are conservative and assume that they don't allow uninit.
546+
.unwrap_or(false)
548547
}
549548

550549
/// Gets an iterator over all predicates which apply to the given item.

tests/ui/uninit.rs

+19-4
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33

44
use std::mem::{self, MaybeUninit};
55

6+
union MyOwnMaybeUninit {
7+
value: u8,
8+
uninit: (),
9+
}
10+
611
fn main() {
712
let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
813

9-
// edge case: For now we lint on empty arrays
10-
let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
11-
12-
// edge case: For now we accept unit tuples
14+
// This is OK, because ZSTs do not contain data.
1315
let _: () = unsafe { MaybeUninit::uninit().assume_init() };
1416

1517
// This is OK, because `MaybeUninit` allows uninitialized data.
@@ -21,6 +23,19 @@ fn main() {
2123
// This is OK, because all constitutent types are uninit-compatible.
2224
let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() };
2325

26+
// This is OK, because our own MaybeUninit is just as fine as the one from core.
27+
let _: MyOwnMaybeUninit = unsafe { MaybeUninit::uninit().assume_init() };
28+
29+
// This is OK, because empty arrays don't contain data.
30+
let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
31+
2432
// Was a false negative.
2533
let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
34+
35+
polymorphic::<()>();
36+
37+
fn polymorphic<T>() {
38+
// We are conservative around polymorphic types.
39+
let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
40+
}
2641
}

tests/ui/uninit.stderr

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
error: this call for this type may be undefined behavior
2-
--> $DIR/uninit.rs:7:29
2+
--> $DIR/uninit.rs:12:29
33
|
44
LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
66
|
77
= note: `#[deny(clippy::uninit_assumed_init)]` on by default
88

99
error: this call for this type may be undefined behavior
10-
--> $DIR/uninit.rs:10:31
10+
--> $DIR/uninit.rs:33:29
1111
|
12-
LL | let _: [u8; 0] = unsafe { MaybeUninit::uninit().assume_init() };
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1414

1515
error: this call for this type may be undefined behavior
16-
--> $DIR/uninit.rs:25:29
16+
--> $DIR/uninit.rs:39:29
1717
|
18-
LL | let _: usize = unsafe { mem::MaybeUninit::uninit().assume_init() };
18+
LL | let _: T = unsafe { mem::MaybeUninit::uninit().assume_init() };
1919
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2020

2121
error: aborting due to 3 previous errors

tests/ui/uninit_vec.rs

+27
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ struct MyVec {
77
vec: Vec<u8>,
88
}
99

10+
union MyOwnMaybeUninit {
11+
value: u8,
12+
uninit: (),
13+
}
14+
1015
fn main() {
1116
// with_capacity() -> set_len() should be detected
1217
let mut vec: Vec<u8> = Vec::with_capacity(1000);
@@ -97,4 +102,26 @@ fn main() {
97102
unsafe {
98103
vec.set_len(0);
99104
}
105+
106+
// ZSTs should not be detected
107+
let mut vec: Vec<()> = Vec::with_capacity(1000);
108+
unsafe {
109+
vec.set_len(10);
110+
}
111+
112+
// unions should not be detected
113+
let mut vec: Vec<MyOwnMaybeUninit> = Vec::with_capacity(1000);
114+
unsafe {
115+
vec.set_len(10);
116+
}
117+
118+
polymorphic::<()>();
119+
120+
fn polymorphic<T>() {
121+
// We are conservative around polymorphic types.
122+
let mut vec: Vec<T> = Vec::with_capacity(1000);
123+
unsafe {
124+
vec.set_len(10);
125+
}
126+
}
100127
}

tests/ui/uninit_vec.stderr

+22-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
2-
--> $DIR/uninit_vec.rs:12:5
2+
--> $DIR/uninit_vec.rs:17:5
33
|
44
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,7 +11,7 @@ LL | vec.set_len(200);
1111
= note: `-D clippy::uninit-vec` implied by `-D warnings`
1212

1313
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
14-
--> $DIR/uninit_vec.rs:18:5
14+
--> $DIR/uninit_vec.rs:23:5
1515
|
1616
LL | vec.reserve(1000);
1717
| ^^^^^^^^^^^^^^^^^^
@@ -22,7 +22,7 @@ LL | vec.set_len(200);
2222
= help: initialize the buffer or wrap the content in `MaybeUninit`
2323

2424
error: calling `set_len()` on empty `Vec` creates out-of-bound values
25-
--> $DIR/uninit_vec.rs:24:5
25+
--> $DIR/uninit_vec.rs:29:5
2626
|
2727
LL | let mut vec: Vec<u8> = Vec::new();
2828
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -31,7 +31,7 @@ LL | vec.set_len(200);
3131
| ^^^^^^^^^^^^^^^^
3232

3333
error: calling `set_len()` on empty `Vec` creates out-of-bound values
34-
--> $DIR/uninit_vec.rs:30:5
34+
--> $DIR/uninit_vec.rs:35:5
3535
|
3636
LL | let mut vec: Vec<u8> = Default::default();
3737
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +40,7 @@ LL | vec.set_len(200);
4040
| ^^^^^^^^^^^^^^^^
4141

4242
error: calling `set_len()` on empty `Vec` creates out-of-bound values
43-
--> $DIR/uninit_vec.rs:35:5
43+
--> $DIR/uninit_vec.rs:40:5
4444
|
4545
LL | let mut vec: Vec<u8> = Vec::default();
4646
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL | vec.set_len(200);
4949
| ^^^^^^^^^^^^^^^^
5050

5151
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
52-
--> $DIR/uninit_vec.rs:49:5
52+
--> $DIR/uninit_vec.rs:54:5
5353
|
5454
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL | vec.set_len(200);
6060
= help: initialize the buffer or wrap the content in `MaybeUninit`
6161

6262
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
63-
--> $DIR/uninit_vec.rs:58:5
63+
--> $DIR/uninit_vec.rs:63:5
6464
|
6565
LL | my_vec.vec.reserve(1000);
6666
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL | my_vec.vec.set_len(200);
7171
= help: initialize the buffer or wrap the content in `MaybeUninit`
7272

7373
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
74-
--> $DIR/uninit_vec.rs:63:5
74+
--> $DIR/uninit_vec.rs:68:5
7575
|
7676
LL | my_vec.vec = Vec::with_capacity(1000);
7777
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,7 +82,7 @@ LL | my_vec.vec.set_len(200);
8282
= help: initialize the buffer or wrap the content in `MaybeUninit`
8383

8484
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
85-
--> $DIR/uninit_vec.rs:42:9
85+
--> $DIR/uninit_vec.rs:47:9
8686
|
8787
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
8888
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL | vec.set_len(200);
9292
= help: initialize the buffer or wrap the content in `MaybeUninit`
9393

9494
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
95-
--> $DIR/uninit_vec.rs:45:9
95+
--> $DIR/uninit_vec.rs:50:9
9696
|
9797
LL | vec.reserve(1000);
9898
| ^^^^^^^^^^^^^^^^^^
@@ -101,5 +101,16 @@ LL | vec.set_len(200);
101101
|
102102
= help: initialize the buffer or wrap the content in `MaybeUninit`
103103

104-
error: aborting due to 10 previous errors
104+
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
105+
--> $DIR/uninit_vec.rs:122:9
106+
|
107+
LL | let mut vec: Vec<T> = Vec::with_capacity(1000);
108+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
109+
LL | unsafe {
110+
LL | vec.set_len(10);
111+
| ^^^^^^^^^^^^^^^
112+
|
113+
= help: initialize the buffer or wrap the content in `MaybeUninit`
114+
115+
error: aborting due to 11 previous errors
105116

0 commit comments

Comments
 (0)