Replace some mem::zeroed uses with idiomatic/safer approaches #6
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
You mentioned learning Rust and making a pull requests to offer advice, so here's something:
std::mem::zeroed
can cause unexpected failures where the value it creates should not exist, e.g. a reference cannot ever be null, just creating one triggers UB; if a field in a struct is a reference, it is instant UB to create the struct via zeroed (see a good discussion at rust-lang/rust#52898)Two approaches to avoid needing to use zeroed are in this PR: where a variable is being initialised to zero because it's just going to be replaced (i.e. it's an out param of an FFI call), it's preferred to use
MaybeUninit
to represent this. This semantically changes the operations being performed from:zeroed
, which may not uphold any invariants the type is meant to possessinto:
MaybeUninit
. This is safe; the unsafe-ty now occurs when interacting with the variable (since it's not yet initialised)assume_init
. This also requires unsafe, as it's a declaration that the variable now has a valid representation for its type.You can see this in the PR; it would not be safe to use the
pi
variable prior to checking that the function call to initialise it succeeded, and so it's only after checkingret != 0
that we callassume_init
and can safely interact with the variable.The other zeroed use I replaced was to derive
Default
rather than implement it directly. DerivingDefault
instructs the compiler to defer to aDefault
implementation for every field of the struct. For example, ifGUID
had an invalid representation (type bits set to an incorrect version?), usingzeroed
would break this assumption, whereas usingDefault
defers toGUID
s implementation.Rather than deriving
Default
you could instead callGUID::default
within your implementation ofDefault
for your type, if you're trying to avoid deriving traits. However, in case you weren't aware of derive, it instructs the compiler to provide default (hah) implementations of traits where possible. Default, Copy, Clone, PartialEq, Eq, are all examples of common traits that can be derived rather than written by hand.Love the intersection of low level Windows & Rust, and windbg has been an almost daily tool for many years now.