Skip to content
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

Merged
merged 3 commits into from
Jan 28, 2020

Conversation

matklad
Copy link
Member

@matklad matklad commented Jan 5, 2020

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).

@rust-highfive
Copy link

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.

@matklad
Copy link
Member Author

matklad commented Jan 6, 2020

Oh, this is another spin on #811 actually! But this version of the seems simpler.

@lu-zero
Copy link
Contributor

lu-zero commented Jan 27, 2020

Can you please try to rebase and see if now the tests pass?

@matklad
Copy link
Member Author

matklad commented Jan 27, 2020

rebased!

Copy link
Contributor

@lu-zero lu-zero left a 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()];
Copy link
Member

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

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome hint, thanks!

Copy link
Member Author

@matklad matklad left a 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()];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome hint, thanks!

crates/std_detect/src/detect/cache.rs Outdated Show resolved Hide resolved
@matklad matklad force-pushed the fix-data-race branch 3 times, most recently from 7125312 to 4418cda Compare January 27, 2020 21:16
#[cfg(target_pointer_width = "32")]
const CACHE_BITS: u32 = 31;
#[cfg(target_pointer_width = "64")]
const CACHE_BITS: u32 = 63;
Copy link
Member

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]?

Copy link
Member Author

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")]
Copy link
Member

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")]
Copy link
Member

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?

@matklad matklad force-pushed the fix-data-race branch 4 times, most recently from c978abc to b5eb5f9 Compare January 28, 2020 13:47
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!
@matklad
Copy link
Member Author

matklad commented Jan 28, 2020

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.

@alexcrichton alexcrichton merged commit 9fa96fa into rust-lang:master Jan 28, 2020
@alexcrichton
Copy link
Member

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants