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 a soundness hole allowing multiple mutable borrows #124

Merged
merged 9 commits into from
Nov 1, 2018

Conversation

KodrAus
Copy link
Contributor

@KodrAus KodrAus commented Sep 26, 2018

Fixes #117

cc @eddyb @RalfJung

See #117 for more details, we don't need &'static mut self receivers on Lazy to initialise and get its value. This also has the nice side benefit of making our various Lazy impls have a consistent API.

This is a potentially breaking change, @pietroalbini do you think it would be possible to schedule a crater run? Thanks!

@KodrAus
Copy link
Contributor Author

KodrAus commented Sep 26, 2018

Ah that's a bit of a nuisance... Looks like Cell::new wasn't available in const fns back in 1.21.0.

This means manually setting the value in an unsafe way, because we
can't use `Cell` with the `const INIT` value.
@KodrAus
Copy link
Contributor Author

KodrAus commented Sep 26, 2018

Ok, I've tweaked the heap_lazy impl so it doesn't need &'static mut or Cell. Using ptr::write always feels a little... dirty :) So please scrutinize that implementation.

@eddyb
Copy link
Member

eddyb commented Sep 28, 2018

@KodrAus Somewhere else in the codebase a static mut is generated, right?
That's a problem.

src/heap_lazy.rs Outdated
// have exclusive access to the value field
// The value hasn't been previously initialized
unsafe {
ptr::write(&self.0 as *const _ as *mut _, r);
Copy link
Member

@eddyb eddyb Sep 28, 2018

Choose a reason for hiding this comment

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

You can't turn the &'static self into a mutable pointer without UnsafeCell, this is UB.

Copy link
Contributor Author

@KodrAus KodrAus Sep 28, 2018

Choose a reason for hiding this comment

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

I thought that might be the case. I'll revert this last commit and bump our minimum version to 1.22 so that we can use Cell properly.

We might have to be a bit patient with rolling this one out, the last version bump we did for 1.1.0 was a bit unpopular (to be fair that bumped about 10 versions, instead of 1).

EDIT: Actually it's not 1.24 that we need.

@pietroalbini
Copy link

This is a potentially breaking change, @pietroalbini do you think it would be possible to schedule a crater run? Thanks!

Not at the moment, sorry, the queue is pretty full :(

@KodrAus
Copy link
Contributor Author

KodrAus commented Sep 28, 2018

Somewhere else in the codebase a static mut is generated, right? That's a problem.

@eddyb Ah well spotted! I totally missed the static mut in the macros.

@pietroalbini No problem :) I think we'll hold on to this one for a little while anyways so we don't poison the well with lots of version bumps over a short period.

unsafe {
match self.0 {
match *self.0.as_ptr() {
Some(ref x) => x,
None => unreachable_unchecked(),

Choose a reason for hiding this comment

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

Might be worth a debug_assert!(false) or so?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea 👍 It seems like a fair thing to be more defensive about

@KodrAus
Copy link
Contributor Author

KodrAus commented Oct 30, 2018

Ok, looking around it seems like 1.24.1 is available in most package managers so I think we should be ok to push this through, but as per our policy we'll have to release it as 1.2.0.

@eddyb does this look good to you?

@KodrAus
Copy link
Contributor Author

KodrAus commented Oct 30, 2018

Just noticed that we can close #125 now that we don't use static mut anymore so we don't need any external unsafe blocks.

@eddyb
Copy link
Member

eddyb commented Oct 31, 2018

@KodrAus Looks great now! Assuming @RalfJung agrees, I think this is good to go.

@RalfJung
Copy link

There is so much context around these macros, doesn't make it easier to analyze.^^

For heap_lazy.rs, the only unsafe bit seems to be to get a shared ref into the leaked Box. Seems fine.

inline_lazy.rs returns a shared ref into a Cell, but that Cell will never get mutated again so this also seems fine.

(I think this could be further optimized with Cell<MaybeInitialized<T>>, avoiding the Option entirely, but that is a separate problem.)

@KodrAus
Copy link
Contributor Author

KodrAus commented Nov 1, 2018

I think this could be further optimized with Cell<MaybeInitialized>

Ah good idea. I've added a FIXME for replacing Option with some kind of MaybeInitialized. That might be a fun thing for someone to contribute along with some benches :)

It sounds like this is ready to merge so I'll go ahead and do that now, but will leave it for a day or two before pushing to crates.io so we can opportunistically bundle #130 too.

@KodrAus KodrAus merged commit daf05aa into rust-lang-nursery:master Nov 1, 2018
@KodrAus KodrAus deleted the fix/static-mut branch November 1, 2018 00:43
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.

4 participants