Skip to content

Commit 114c948

Browse files
authored
Rollup merge of rust-lang#66044 - RalfJung:uninit-lint, r=oli-obk
Improve uninit/zeroed lint * Also warn when creating a raw pointer with a NULL vtable. * Also identify `MaybeUninit::uninit().assume_init()` and `MaybeUninit::zeroed().assume_init()` as dangerous.
2 parents c4b380f + bb37d00 commit 114c948

File tree

7 files changed

+104
-9
lines changed

7 files changed

+104
-9
lines changed

src/libcore/mem/maybe_uninit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,7 @@ impl<T> MaybeUninit<T> {
440440
/// ```
441441
#[stable(feature = "maybe_uninit", since = "1.36.0")]
442442
#[inline(always)]
443+
#[cfg_attr(all(not(bootstrap)), rustc_diagnostic_item = "assume_init")]
443444
pub unsafe fn assume_init(self) -> T {
444445
intrinsics::panic_if_uninhabited::<T>();
445446
ManuallyDrop::into_inner(self.value)

src/librustc/lint/context.rs

+3
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> {
699699

700700
/// Check if a `DefId`'s path matches the given absolute type path usage.
701701
///
702+
/// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`;
703+
/// inherent `impl` blocks are matched with the name of the type.
704+
///
702705
/// # Examples
703706
///
704707
/// ```rust,ignore (no context or def id available)

src/librustc_lint/builtin.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -1909,8 +1909,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19091909
// `Invalid` represents the empty string and matches that.
19101910
const TRANSMUTE_PATH: &[Symbol] =
19111911
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];
1912+
const MU_ZEROED_PATH: &[Symbol] =
1913+
&[sym::core, sym::mem, sym::maybe_uninit, sym::MaybeUninit, sym::zeroed];
1914+
const MU_UNINIT_PATH: &[Symbol] =
1915+
&[sym::core, sym::mem, sym::maybe_uninit, sym::MaybeUninit, sym::uninit];
19121916

19131917
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind {
1918+
// Find calls to `mem::{uninitialized,zeroed}` methods.
19141919
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
19151920
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
19161921

@@ -1925,8 +1930,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19251930
return Some(InitKind::Zeroed);
19261931
}
19271932
}
1928-
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
1929-
// `MaybeUninit::uninit().assume_init()`.
1933+
}
1934+
} else if let hir::ExprKind::MethodCall(_, _, ref args) = expr.kind {
1935+
// Find problematic calls to `MaybeUninit::assume_init`.
1936+
let def_id = cx.tables.type_dependent_def_id(expr.hir_id)?;
1937+
if cx.tcx.is_diagnostic_item(sym::assume_init, def_id) {
1938+
// This is a call to *some* method named `assume_init`.
1939+
// See if the `self` parameter is one of the dangerous constructors.
1940+
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind {
1941+
if let hir::ExprKind::Path(ref qpath) = path_expr.kind {
1942+
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?;
1943+
if cx.match_def_path(def_id, MU_ZEROED_PATH) {
1944+
return Some(InitKind::Zeroed);
1945+
} else if cx.match_def_path(def_id, MU_UNINIT_PATH) {
1946+
return Some(InitKind::Uninit);
1947+
}
1948+
}
1949+
}
19301950
}
19311951
}
19321952

@@ -1947,6 +1967,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
19471967
Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)),
19481968
FnPtr(..) => Some((format!("Function pointers must be non-null"), None)),
19491969
Never => Some((format!("The never type (`!`) has no valid value"), None)),
1970+
RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) => // raw ptr to dyn Trait
1971+
Some((format!("The vtable of a wide raw pointer must be non-null"), None)),
19501972
// Primitive types with other constraints.
19511973
Bool if init == InitKind::Uninit =>
19521974
Some((format!("Booleans must be `true` or `false`"), None)),

src/librustc_lint/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#![feature(box_patterns)]
1616
#![feature(box_syntax)]
1717
#![feature(nll)]
18+
#![feature(matches_macro)]
1819

1920
#![recursion_limit="256"]
2021

src/libsyntax_pos/symbol.rs

+4
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ symbols! {
148148
associated_type_bounds,
149149
associated_type_defaults,
150150
associated_types,
151+
assume_init,
151152
async_await,
152153
async_closure,
153154
attr,
@@ -417,6 +418,8 @@ symbols! {
417418
match_beginning_vert,
418419
match_default_bindings,
419420
may_dangle,
421+
maybe_uninit,
422+
MaybeUninit,
420423
mem,
421424
member_constraints,
422425
message,
@@ -709,6 +712,7 @@ symbols! {
709712
underscore_imports,
710713
underscore_lifetimes,
711714
uniform_paths,
715+
uninit,
712716
uninitialized,
713717
universal_impl_trait,
714718
unmarked_api,

src/test/ui/lint/uninitialized-zeroed.rs

+9
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ fn main() {
6767
let _val: NonNull<i32> = mem::zeroed(); //~ ERROR: does not permit zero-initialization
6868
let _val: NonNull<i32> = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
6969

70+
let _val: *const dyn Send = mem::zeroed(); //~ ERROR: does not permit zero-initialization
71+
let _val: *const dyn Send = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
72+
7073
// Things that can be zero, but not uninit.
7174
let _val: bool = mem::zeroed();
7275
let _val: bool = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
@@ -82,10 +85,16 @@ fn main() {
8285
let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
8386
let _val: NonZeroU32 = mem::transmute(0); //~ ERROR: does not permit zero-initialization
8487

88+
// `MaybeUninit` cases
89+
let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init(); //~ ERROR: does not permit zero-initialization
90+
let _val: NonNull<i32> = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized
91+
let _val: bool = MaybeUninit::uninit().assume_init(); //~ ERROR: does not permit being left uninitialized
92+
8593
// Some more types that should work just fine.
8694
let _val: Option<&'static i32> = mem::zeroed();
8795
let _val: Option<fn()> = mem::zeroed();
8896
let _val: MaybeUninit<&'static i32> = mem::zeroed();
8997
let _val: i32 = mem::zeroed();
98+
let _val: bool = MaybeUninit::zeroed().assume_init();
9099
}
91100
}

src/test/ui/lint/uninitialized-zeroed.stderr

+62-7
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,30 @@ LL | let _val: NonNull<i32> = mem::uninitialized();
307307
|
308308
= note: std::ptr::NonNull<i32> must be non-null
309309

310+
error: the type `*const dyn std::marker::Send` does not permit zero-initialization
311+
--> $DIR/uninitialized-zeroed.rs:70:37
312+
|
313+
LL | let _val: *const dyn Send = mem::zeroed();
314+
| ^^^^^^^^^^^^^
315+
| |
316+
| this code causes undefined behavior when executed
317+
| help: use `MaybeUninit<T>` instead
318+
|
319+
= note: The vtable of a wide raw pointer must be non-null
320+
321+
error: the type `*const dyn std::marker::Send` does not permit being left uninitialized
322+
--> $DIR/uninitialized-zeroed.rs:71:37
323+
|
324+
LL | let _val: *const dyn Send = mem::uninitialized();
325+
| ^^^^^^^^^^^^^^^^^^^^
326+
| |
327+
| this code causes undefined behavior when executed
328+
| help: use `MaybeUninit<T>` instead
329+
|
330+
= note: The vtable of a wide raw pointer must be non-null
331+
310332
error: the type `bool` does not permit being left uninitialized
311-
--> $DIR/uninitialized-zeroed.rs:72:26
333+
--> $DIR/uninitialized-zeroed.rs:75:26
312334
|
313335
LL | let _val: bool = mem::uninitialized();
314336
| ^^^^^^^^^^^^^^^^^^^^
@@ -319,7 +341,7 @@ LL | let _val: bool = mem::uninitialized();
319341
= note: Booleans must be `true` or `false`
320342

321343
error: the type `Wrap<char>` does not permit being left uninitialized
322-
--> $DIR/uninitialized-zeroed.rs:75:32
344+
--> $DIR/uninitialized-zeroed.rs:78:32
323345
|
324346
LL | let _val: Wrap<char> = mem::uninitialized();
325347
| ^^^^^^^^^^^^^^^^^^^^
@@ -334,7 +356,7 @@ LL | struct Wrap<T> { wrapped: T }
334356
| ^^^^^^^^^^
335357

336358
error: the type `NonBig` does not permit being left uninitialized
337-
--> $DIR/uninitialized-zeroed.rs:78:28
359+
--> $DIR/uninitialized-zeroed.rs:81:28
338360
|
339361
LL | let _val: NonBig = mem::uninitialized();
340362
| ^^^^^^^^^^^^^^^^^^^^
@@ -345,7 +367,7 @@ LL | let _val: NonBig = mem::uninitialized();
345367
= note: NonBig must be initialized inside its custom valid range
346368

347369
error: the type `&'static i32` does not permit zero-initialization
348-
--> $DIR/uninitialized-zeroed.rs:81:34
370+
--> $DIR/uninitialized-zeroed.rs:84:34
349371
|
350372
LL | let _val: &'static i32 = mem::transmute(0usize);
351373
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -356,7 +378,7 @@ LL | let _val: &'static i32 = mem::transmute(0usize);
356378
= note: References must be non-null
357379

358380
error: the type `&'static [i32]` does not permit zero-initialization
359-
--> $DIR/uninitialized-zeroed.rs:82:36
381+
--> $DIR/uninitialized-zeroed.rs:85:36
360382
|
361383
LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
362384
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -367,7 +389,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize));
367389
= note: References must be non-null
368390

369391
error: the type `std::num::NonZeroU32` does not permit zero-initialization
370-
--> $DIR/uninitialized-zeroed.rs:83:32
392+
--> $DIR/uninitialized-zeroed.rs:86:32
371393
|
372394
LL | let _val: NonZeroU32 = mem::transmute(0);
373395
| ^^^^^^^^^^^^^^^^^
@@ -377,5 +399,38 @@ LL | let _val: NonZeroU32 = mem::transmute(0);
377399
|
378400
= note: std::num::NonZeroU32 must be non-null
379401

380-
error: aborting due to 30 previous errors
402+
error: the type `std::ptr::NonNull<i32>` does not permit zero-initialization
403+
--> $DIR/uninitialized-zeroed.rs:89:34
404+
|
405+
LL | let _val: NonNull<i32> = MaybeUninit::zeroed().assume_init();
406+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
407+
| |
408+
| this code causes undefined behavior when executed
409+
| help: use `MaybeUninit<T>` instead
410+
|
411+
= note: std::ptr::NonNull<i32> must be non-null
412+
413+
error: the type `std::ptr::NonNull<i32>` does not permit being left uninitialized
414+
--> $DIR/uninitialized-zeroed.rs:90:34
415+
|
416+
LL | let _val: NonNull<i32> = MaybeUninit::uninit().assume_init();
417+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
418+
| |
419+
| this code causes undefined behavior when executed
420+
| help: use `MaybeUninit<T>` instead
421+
|
422+
= note: std::ptr::NonNull<i32> must be non-null
423+
424+
error: the type `bool` does not permit being left uninitialized
425+
--> $DIR/uninitialized-zeroed.rs:91:26
426+
|
427+
LL | let _val: bool = MaybeUninit::uninit().assume_init();
428+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
429+
| |
430+
| this code causes undefined behavior when executed
431+
| help: use `MaybeUninit<T>` instead
432+
|
433+
= note: Booleans must be `true` or `false`
434+
435+
error: aborting due to 35 previous errors
381436

0 commit comments

Comments
 (0)