-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Improve uninit/zeroed lint #66044
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve uninit/zeroed lint #66044
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1911,8 +1911,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { | |
// `Invalid` represents the empty string and matches that. | ||
const TRANSMUTE_PATH: &[Symbol] = | ||
&[sym::core, sym::intrinsics, kw::Invalid, sym::transmute]; | ||
const MU_ZEROED_PATH: &[Symbol] = | ||
&[sym::core, sym::mem, sym::maybe_uninit, sym::MaybeUninit, sym::zeroed]; | ||
const MU_UNINIT_PATH: &[Symbol] = | ||
&[sym::core, sym::mem, sym::maybe_uninit, sym::MaybeUninit, sym::uninit]; | ||
|
||
if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind { | ||
// Find calls to `mem::{uninitialized,zeroed}` methods. | ||
if let hir::ExprKind::Path(ref qpath) = path_expr.kind { | ||
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; | ||
|
||
|
@@ -1927,8 +1932,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { | |
return Some(InitKind::Zeroed); | ||
} | ||
} | ||
// FIXME: Also detect `MaybeUninit::zeroed().assume_init()` and | ||
// `MaybeUninit::uninit().assume_init()`. | ||
} | ||
} else if let hir::ExprKind::MethodCall(ref path, _, ref args) = expr.kind { | ||
// Find problematic calls to `MaybeUninit::assume_init`. | ||
if path.ident.name == sym::assume_init { | ||
// This is a call to *some* method named `assume_init`. | ||
// See if the `self` parameter is one of the dangerous constructors. | ||
if let hir::ExprKind::Call(ref path_expr, _) = args[0].kind { | ||
if let hir::ExprKind::Path(ref qpath) = path_expr.kind { | ||
let def_id = cx.tables.qpath_res(qpath, path_expr.hir_id).opt_def_id()?; | ||
if cx.match_def_path(def_id, MU_ZEROED_PATH) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this (and the other one below) also use diagnostics items? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, see #66075. This is partially pre-existing. I didn't feel like rewriting the entire lint at once.^^ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea we should be moving away from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @RalfJung Sure that's fair about the old code... but these are additions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I guess this is as good as any a time to resolve the first bullet point from that issue. Not sure when I'll get to it, though. |
||
return Some(InitKind::Zeroed); | ||
} else if cx.match_def_path(def_id, MU_UNINIT_PATH) { | ||
return Some(InitKind::Uninit); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -1949,6 +1968,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidValue { | |
Adt(..) if ty.is_box() => Some((format!("`Box` must be non-null"), None)), | ||
FnPtr(..) => Some((format!("Function pointers must be non-null"), None)), | ||
Never => Some((format!("The never type (`!`) has no valid value"), None)), | ||
RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) => // raw ptr to dyn Trait | ||
Some((format!("The vtable of a wide raw pointer must be non-null"), None)), | ||
// Primitive types with other constraints. | ||
Bool if init == InitKind::Uninit => | ||
Some((format!("Booleans must be `true` or `false`"), None)), | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one seems odd to me. I am comparing just the name of the method -- but what if there is a trait or another type or so that also had this method? This looks like I am working pre-resolution, which seems fragile. Isn't there any way to get the full path to the method that will actually be called here?
I looked at clippy but couldn't find anything less fragile there either. Cc @oli-obk @Manishearth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use diagnostics items instead? #60966
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, I have an
Option<HirId>
; I guess I could unwrap that and then callowner_def_id
to get theDefId
thatis_diagnostic_item
needs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, that does not work. The lint just never fires. Looks like the
HirId
I get there is not pointing to the method being called -- that kind of makes sense if the information we have here is pre-method-resolution. (Probably it's theHirId
of the method call itself.)For
Call
, I can callto get the
def_id
of the callee. Isn't there something similar forMethodCall
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, maybe I need to construct a
QPath::TypeRelative
? I have aPathSegment
, but I'd still also need aTy
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I found a way:
Here,
expr
is theMethodCall
itself.