-
Notifications
You must be signed in to change notification settings - Fork 276
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
Fix race condition in feature cache on 32 platforms #837
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @gnzlbg (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
Oh, this is another spin on #811 actually! But this version of the seems simpler. |
Can you please try to rebase and see if now the tests pass? |
19fa496
to
d7c4c0f
Compare
rebased! |
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.
It looks fine to me, @gnzlbg and @alexcrichton do you agree?
/// Feature cache with capacity for `CACHE_CAPACITY` features. | ||
/// This global variable is a cache of the features supported by the CPU. | ||
#[cfg(target_pointer_width = "32")] | ||
static CACHE: [Cache; 2] = [Cache::uninitialized(), Cache::uninitialized()]; |
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.
Instead of defining this differently on each platform, could this perhaps be unified a bit like so?
#[cfg(target_pointer_width = "64")]
static CACHE: [Cache; 1] = [Cache::uninitialized()];
#[cfg(target_pointer_width = "32")]
static CACHE: [Cache; 2] = [Cache::uninitialized(), Cache::uninitialized()];
I think that'd help cut down on the #[cfg]
traffic
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.
Awesome hint, thanks!
d7c4c0f
to
34b6e63
Compare
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.
Updated!
/// Feature cache with capacity for `CACHE_CAPACITY` features. | ||
/// This global variable is a cache of the features supported by the CPU. | ||
#[cfg(target_pointer_width = "32")] | ||
static CACHE: [Cache; 2] = [Cache::uninitialized(), Cache::uninitialized()]; |
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.
Awesome hint, thanks!
7125312
to
4418cda
Compare
#[cfg(target_pointer_width = "32")] | ||
const CACHE_BITS: u32 = 31; | ||
#[cfg(target_pointer_width = "64")] | ||
const CACHE_BITS: u32 = 63; |
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.
Could this constant either be removed or defined in terms of mem::size_of::<usize>()
instead of using #[cfg]
?
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.
Actually it could!
@@ -194,8 +171,18 @@ pub(crate) fn test<F>(bit: u32, f: F) -> bool | |||
where | |||
F: FnOnce() -> Initializer, | |||
{ | |||
if CACHE.is_uninitialized() { | |||
initialize(f()); | |||
#[cfg(target_pointer_width = "32")] |
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.
I think this #[cfg]
could be avoided and the math here could be done with mem::size_of::<usize>()
as well
#[inline] | ||
fn do_initialize(value: Initializer) { | ||
CACHE[0].initialize((value.0) as usize & CACHE_MASK); | ||
#[cfg(target_pointer_width = "32")] |
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.
Like elsewhere, can the #[cfg]
be removed here to work with shifts instead?
c978abc
to
b5eb5f9
Compare
If we observe that the second word is initialized, we can't really assume that the first is initialized as well. So check each word separately.
Better SeqCst than sorry!
b5eb5f9
to
22231ea
Compare
I've tried to get rid of cfgs using clever indexing, but unfortunately rustc was just smart enough to figure out that I try to index out of bounds into array and just dumb enough to not realize that it's dead code :) In the last commit, I've just made both paths use two slots. |
65b65b8
to
9b9cf9f
Compare
👍 |
If we observe that the second word is initialized, we can't really
assume that the first is initialized as well. So check each word
separately.
r? @gnzlbg
I've found this by just looking at the code, and I didn't actually test this (
cargo test --target i686-unknown-linux-gnu
failed with some build.rs error which I haven't looked into).