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

Automatically use the allocation-free API for Rust 1.27.0+. #103

Merged
merged 5 commits into from
Aug 2, 2018
Merged

Conversation

anp
Copy link
Contributor

@anp anp commented Jun 22, 2018

Introduces a buildscript to help decide which implementation to use by default. If using a version of Rust >= 1.27.0, what I've renamed the "inline" implementation will be automatically selected. On older versions of Rust, what I'm calling the "heap" implementation (previously the default one) will be selected. Originally I had removed the nightly feature entirely, but then I decided to keep it to preserve semver-major compatibility (let me know if you think this is taking compatibility too far -- it'd be nice to clean the feature up).

Another decision I made was to re-use the rustc_version crate for parsing version numbers rather than rolling our own as @BurntSushi did for regex. This does add build-time dependencies although no extra crates will be added to consumers' binaries. I think it improves clarity slightly and reduces overall churn. Happy to discuss if there's disagreement though.

Test plan: tests pass locally with 1.21.0, 1.27.0, and nightly-2018-06-20. Also will see what CI says.

Closes #102.

@anp
Copy link
Contributor Author

anp commented Jun 22, 2018

Looks like nightly builds are failing right now for what I can only assume is an unrelated reason. The 1.21.0 and stable tests are passing on travis.

@KodrAus
Copy link
Contributor

KodrAus commented Jun 23, 2018

Thanks @anp! I'll dig into this later today.

Yeh it looks like the latest nightly is a bit broken...

@KodrAus
Copy link
Contributor

KodrAus commented Jun 24, 2018

Thanks @anp! I think we could simplify the cfg attributes a bit if we roll the nightly feature check into the version check in the build script. That way we only set the use_heap_impl if we're on a non-nightly compiler before 1.27.0 and leave nightly as a marker for spin, which only compiles on nightly.

What do you think?

@anp
Copy link
Contributor Author

anp commented Jun 27, 2018

@KodrAus I like that idea a lot. Want to take a look at this approach (assuming CI passes after I write this)?

@anp
Copy link
Contributor Author

anp commented Jun 27, 2018

I'm not able to reproduce this compiletest failure locally, but it seems like it's probably tripping up on an error message whose format has changed.

KodrAus
KodrAus previously approved these changes Jun 28, 2018
Copy link
Contributor

@KodrAus KodrAus left a comment

Choose a reason for hiding this comment

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

Thanks @anp! This looks good to me.

We've fixed up the compilefail test in #104. Would you like to rebase, just so we can sanity check CI?

@anp
Copy link
Contributor Author

anp commented Jun 28, 2018

Rebased and squashed, thanks for the fast turnaround on CI repair!

@anp
Copy link
Contributor Author

anp commented Jun 28, 2018

@KodrAus looks like we're all green.

@anp
Copy link
Contributor Author

anp commented Jun 28, 2018

Actually, can we hold off on merging for a bit?

Specifically I want to ask about a soundness issue before this becomes part of the de facto 1.0 API for the crate, but it's late here.

@eddyb
Copy link
Member

eddyb commented Jun 28, 2018

The reasons to hold are both simplification (#102 (comment)) and soundness (#105).

anp added 3 commits July 8, 2018 13:55
1.27.0 stabilized hint::unreachable, allowing the previously
nightly-only API to be used on stable.

The version detection can still be overridden using `cfg`s
(or their related environment variables through cargo), and both
the nightly and spin_no_std features are preserved for compatibility.
This is to patch an obscure soundness hole.

With the fields public, it is possible to for a consumer crate to access and call the std::sync::Once without assigning the correct value to the pointer in the tuple's first field, making it possible to later deref a null pointer from safe code.

However now that lazy_static targets 1.21.0+, we can use an associated constant in the __lazy_static_create macro instead of requiring consumers to literally construct the inner values post-expansion. This is technically a breaking change, but given that any existing use of these inner fields is very likely to cause unsoundness I think it's consistent with Rust's semver policy to make this change and stay at 1.0.
@anp
Copy link
Contributor Author

anp commented Jul 8, 2018

Alright, thanks for being patient with me here. Unfortunately it's not possible to achieve all of the cleanup @eddyb suggested, as the inline impl requires Drop in statics, which wasn't stable until 1.22.0. If bumping the minimum compiler version of lazy_static to 1.22 is on the table, then we could go from 3 implementations to 2. Since I'm guessing it's not on the table (for good reasons), I've pushed some new commits to try to maximize outcomes for all consumers:

  • Fix the soundness problem (albeit an obscure one) in the inline impl
  • Also fix the soundness problem in the heap impl (this is technically a breaking change, see commit message) -- I don't think this is a requirement to enable the optimization for everyone but I think it's basically a non-breaking change and I think having lazy_static be as airtight as possible would be great
  • Finally I added a polyfill for core::hint::unreachable_unchecked that allows consumers at versions 1.22+ to use the allocation-free implementation by default

@KodrAus KodrAus dismissed their stale review July 9, 2018 05:59

out of date

@anp
Copy link
Contributor Author

anp commented Jul 9, 2018

Looks like the AppVeyor build failed due to network timeout -- is there an easy way to restart those?

@KodrAus
Copy link
Contributor

KodrAus commented Jul 9, 2018

Thanks @anp! This looks good to me with a quick scan on mobile. The rejigging of features looks like a good change 👍 I'll dig through again shortly.

Unfortunately there isn't an easy way to retry AppVeyor builds short of updating your branch. Their account model is a bit clumsier for organization ownership so a lot of projects end up tied to individual users.

…le_unchecked.

Also editing the commit message to force a CI run. Woo!
@anp
Copy link
Contributor Author

anp commented Jul 9, 2018

OK, I edited a commit message and re-pushed. CI is re-running.

@anp
Copy link
Contributor Author

anp commented Jul 10, 2018

CI passed this time. I think this is good to go, pending review of the extra complexity I've added to the build matrix.

}

#[cfg(lazy_static_core_unreachable_unchecked)]
use core::hint::unreachable_unchecked;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to bother with core::hint::unreachable_unchecked at all with our polyfill?

Copy link
Member

Choose a reason for hiding this comment

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

Nope, we can wait until the minimum version is raised for some other reason, to switch to the std version.

/// Polyfill for core::hint::unreachable_unchecked. Included to support Rust prior to 1.27. See
/// [issue #102](https://github.com/rust-lang-nursery/lazy-static.rs/issues/102#issuecomment-400959779)
/// for details.
unsafe fn unreachable_unchecked() -> ! {
Copy link
Member

Choose a reason for hiding this comment

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

You don't need to do this yourself, turns out, https://docs.rs/unreachable exists.

Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I think it's reasonable in this case for lazy_static to include this very simple function to avoid bringing in 2 additional dependencies.

Copy link
Member

Choose a reason for hiding this comment

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

Ah that's fine, if the rationalization is added to the comment.

@anp
Copy link
Contributor Author

anp commented Jul 10, 2018

Thanks for the feedback, addressed both of these.

@anp
Copy link
Contributor Author

anp commented Jul 16, 2018

@KodrAus ping

Copy link
Contributor

@KodrAus KodrAus left a comment

Choose a reason for hiding this comment

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

Thanks for your patience @anp! This looks good to me. We'll do a crater run to sniff out any breakage from the visibility changes.

@anp
Copy link
Contributor Author

anp commented Aug 2, 2018

Looks like the crater run came back clean!

@KodrAus KodrAus merged commit e714bee into rust-lang-nursery:master Aug 2, 2018
@KodrAus
Copy link
Contributor

KodrAus commented Aug 2, 2018

Merged 🎉 We might have a build fail on master again because of #110

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.

3 participants