-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 std::sys::windows::compat #76979
Improve std::sys::windows::compat #76979
Conversation
(rust_highfive has picked a reviewer for you, use r? to override) |
This comment has been minimized.
This comment has been minimized.
mem::transmute::<usize, F>(addr)($($argname),*) | ||
#[allow(dead_code)] | ||
pub fn is_available() -> bool { | ||
addr() != fallback as usize |
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.
Function pointer equality is not well defined, since we give functions to LLVM as unnamed_addr
which means their address is claimed to not be significant to the execution of the program. See #54685. This expression can evaluate to unequal even if lookup failed, and can evaluate to equal even if lookup succeeded. Is there a different way to implement is_available, or is there some reason to believe this wouldn't hit bizarre behavior?
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.
Oh, interesting. Thanks.
If I understand correctly, unnamed_addr
allows for merging functions. Meaning that f1 == f2
might give true for different functions, but not that f1 == f1
might give false for the same function. So false positives, but not false negatives. That would be fine here. The functions loaded from GetProcAddress
are definitely not merged with fallback
(since they come from external dll
), and that's the only one that matters. If multiple fallback
functions happen to have the same address for example, that's fine.
So the question here is whether 'the address is not significant' means 'not significant but at least constant', or that it may assumef != f
.
Disabling unnamed_addr
on fallback
would also work, but it seems there's no way to do that in Rust.
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, @eddyb tells me rustc itself might duplicate functions too. So, in this snippet it could mean that fallback as usize
(which is short for fallback as fn() as usize
) might result in a copy of fallback
. Using a static FALLBACK: fn(..) = fallback;
and using that static instead should prevent that. The assumption that that works is already made in core
:
rust/library/core/src/fmt/mod.rs
Lines 246 to 267 in 9cba260
// This guarantees a single stable value for the function pointer associated with | |
// indices/counts in the formatting infrastructure. | |
// | |
// Note that a function defined as such would not be correct as functions are | |
// always tagged unnamed_addr with the current lowering to LLVM IR, so their | |
// address is not considered important to LLVM and as such the as_usize cast | |
// could have been miscompiled. In practice, we never call as_usize on non-usize | |
// containing data (as a matter of static generation of the formatting | |
// arguments), so this is merely an additional check. | |
// | |
// We primarily want to ensure that the function pointer at `USIZE_MARKER` has | |
// an address corresponding *only* to functions that also take `&usize` as their | |
// first argument. The read_volatile here ensures that we can safely ready out a | |
// usize from the passed reference and that this address does not point at a | |
// non-usize taking function. | |
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] | |
static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| { | |
// SAFETY: ptr is a reference | |
let _v: usize = unsafe { crate::ptr::read_volatile(ptr) }; | |
loop {} | |
}; | |
See also #54685 (comment)
I'll update the PR to do the same.
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.
Rebased and added 63b6007 to fix this issue.
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.
FWIW this looks fine to me now.
- Module name can now be any string, not just an ident. (Not all Windows api modules are valid Rust identifiers.) - Adds c::FuncName::is_available() for checking if a function is really available without having to do a duplicate lookup. - Add comment explaining the lack of locking. - Use `$_:block` to simplify the macro_rules. - Apply allow(unused_variables) only to the fallback instead of everything.
aefcd26
to
eca1661
Compare
eca1661
to
63b6007
Compare
@bors r+ |
📌 Commit 63b6007 has been approved by |
…llback-check, r=dtolnay Improve std::sys::windows::compat Improves the compat_fn macro in sys::windows, which is used for conditionally loading APIs that might not be available. - The module (dll) name can now be any string, not just an ident. (Not all Windows api modules are valid Rust identifiers. E.g. `WaitOnAddress` comes from `API-MS-Win-Core-Synch-l1-2-0.dll`.) - Adds `FuncName::is_available()` for checking if a function is really available without having to do a duplicate lookup. - Add comment explaining the lack of locking. - Use `$_:block` to simplify the macro_rules. - Apply `allow(unused_variables)` only to the fallback instead of everything. --- The second point (`is_available()`) simplifies code that needs to pick an implementation depening on what is available, like `sys/windows/mutex.rs`. Before this change, it'd do its own lookup and keep its own `AtomicUsize` to track the result. Now it can just use `c::AcquireSRWLockExclusive::is_available()` directly. This will also be useful when park/unpark/CondVar/etc. get improved implementations (e.g. from parking_lot or something else), as the best APIs for those are not available before Windows 8.
Rollup of 11 pull requests Successful merges: - rust-lang#76851 (Fix 'FIXME' about using NonZeroU32 instead of u32.) - rust-lang#76979 (Improve std::sys::windows::compat) - rust-lang#77111 (Stabilize slice_ptr_range.) - rust-lang#77147 (Split sys_common::Mutex in StaticMutex and MovableMutex.) - rust-lang#77312 (Remove outdated line from `publish_toolstate` hook) - rust-lang#77362 (Fix is_absolute on WASI) - rust-lang#77375 (rustc_metadata: Do not forget to encode inherent impls for foreign types) - rust-lang#77385 (Improve the example for ptr::copy) - rust-lang#77389 (Fix some clippy lints) - rust-lang#77399 (BTreeMap: use Unique::from to avoid a cast where type information exists) - rust-lang#77429 (Link `new` method in `DefautHasher`s doc) Failed merges: r? `@ghost`
Improves the compat_fn macro in sys::windows, which is used for conditionally loading APIs that might not be available.
WaitOnAddress
comes fromAPI-MS-Win-Core-Synch-l1-2-0.dll
.)FuncName::is_available()
for checking if a function is really available without having to do a duplicate lookup.$_:block
to simplify the macro_rules.allow(unused_variables)
only to the fallback instead of everything.The second point (
is_available()
) simplifies code that needs to pick an implementation depening on what is available, likesys/windows/mutex.rs
. Before this change, it'd do its own lookup and keep its ownAtomicUsize
to track the result. Now it can just usec::AcquireSRWLockExclusive::is_available()
directly.This will also be useful when park/unpark/CondVar/etc. get improved implementations (e.g. from parking_lot or something else), as the best APIs for those are not available before Windows 8.