Skip to content

Commit a9efa73

Browse files
committed
invalid_value: also detect transmute-from-0 (seen in the wild)
1 parent 9ab1d5c commit a9efa73

File tree

3 files changed

+110
-45
lines changed

3 files changed

+110
-45
lines changed

src/librustc_lint/builtin.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,12 +1879,38 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
18791879
#[derive(Debug, Copy, Clone, PartialEq)]
18801880
enum InitKind { Zeroed, Uninit };
18811881

1882+
/// Information about why a type cannot be initialized this way.
1883+
/// Contains an error message and optionally a span to point at.
1884+
type InitError = (String, Option<Span>);
1885+
1886+
/// Test if this constant is all-0.
1887+
fn is_zero(expr: &hir::Expr) -> bool {
1888+
use hir::ExprKind::*;
1889+
use syntax::ast::LitKind::*;
1890+
match &expr.node {
1891+
Lit(lit) =>
1892+
if let Int(i, _) = lit.node {
1893+
i == 0
1894+
} else {
1895+
false
1896+
},
1897+
Tup(tup) =>
1898+
tup.iter().all(is_zero),
1899+
_ =>
1900+
false
1901+
}
1902+
}
1903+
18821904
/// Determine if this expression is a "dangerous initialization".
18831905
fn is_dangerous_init(cx: &LateContext<'_, '_>, expr: &hir::Expr) -> Option<InitKind> {
18841906
const ZEROED_PATH: &[Symbol] = &[sym::core, sym::mem, sym::zeroed];
18851907
const UININIT_PATH: &[Symbol] = &[sym::core, sym::mem, sym::uninitialized];
1908+
// `transmute` is inside an anonymous module (the `extern` block?);
1909+
// `Invalid` represents the empty string and matches that.
1910+
const TRANSMUTE_PATH: &[Symbol] =
1911+
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute];
18861912

1887-
if let hir::ExprKind::Call(ref path_expr, ref _args) = expr.node {
1913+
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.node {
18881914
if let hir::ExprKind::Path(ref qpath) = path_expr.node {
18891915
if let Some(def_id) = cx.tables.qpath_res(qpath, path_expr.hir_id)
18901916
.opt_def_id()
@@ -1895,20 +1921,20 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue {
18951921
if cx.match_def_path(def_id, &UININIT_PATH) {
18961922
return Some(InitKind::Uninit);
18971923
}
1924+
if cx.match_def_path(def_id, &TRANSMUTE_PATH) {
1925+
if is_zero(&args[0]) {
1926+
return Some(InitKind::Zeroed);
1927+
}
1928+
}
18981929
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and
18991930
// `MaybeUninit::uninit().assume_init()`.
1900-
// FIXME: Also detect `transmute` from 0.
19011931
}
19021932
}
19031933
}
19041934

19051935
None
19061936
}
19071937

1908-
/// Information about why a type cannot be initialized this way.
1909-
/// Contains an error message and optionally a span to point at.
1910-
type InitError = (String, Option<Span>);
1911-
19121938
/// Return `Some` only if we are sure this type does *not*
19131939
/// allow zero initialization.
19141940
fn ty_find_init_error<'tcx>(

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#![deny(invalid_value)]
88

99
use std::mem::{self, MaybeUninit};
10+
use std::num::NonZeroU32;
1011

1112
enum Void {}
1213

@@ -75,6 +76,11 @@ fn main() {
7576
let _val: NonBig = mem::zeroed();
7677
let _val: NonBig = mem::uninitialized(); //~ ERROR: does not permit being left uninitialized
7778

79+
// Transmute-from-0
80+
let _val: &'static i32 = mem::transmute(0usize); //~ ERROR: does not permit zero-initialization
81+
let _val: &'static [i32] = mem::transmute((0usize, 0usize)); //~ ERROR: does not permit zero-initialization
82+
let _val: NonZeroU32 = mem::transmute(0); //~ ERROR: does not permit zero-initialization
83+
7884
// Some more types that should work just fine.
7985
let _val: Option<&'static i32> = mem::zeroed();
8086
let _val: Option<fn()> = mem::zeroed();

0 commit comments

Comments
 (0)