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

Send/Sync audit for libcollections #22715

Merged
merged 2 commits into from Feb 26, 2015
Merged

Conversation

edwardw
Copy link
Contributor

@edwardw edwardw commented Feb 23, 2015

In the process, also replaces two raw mutable pointers with Unique to
spell out the ownership semantics.

cc #22709

@rust-highfive
Copy link
Collaborator

r? @pcwalton

(rust_highfive has picked a reviewer for you, use r? to override)

@edwardw
Copy link
Contributor Author

edwardw commented Feb 23, 2015

r? @huonw

@rust-highfive rust-highfive assigned huonw and unassigned pcwalton Feb 23, 2015
@@ -200,6 +200,9 @@ struct RawItems<T> {
tail: *const T,
}

unsafe impl<T: Send> Send for RawItems<T> { }
Copy link
Contributor

Choose a reason for hiding this comment

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

IIIII'm not sure this is sound. RawItems is basically for draining values out of an allocation, but doesn't actually own its allocation. Sending this seems unsound?

Also RawItems is 100% internal, so I don't think it needs Send/Sync (only exported inside of MoveTraversalImpl, but you impl Send/Sync on that already).

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 catch. I assumed RawItems is safe since it has Iterator and DoubleEndedIterator implementations which take &mut self. But by closer inspection, the real mutations are all in unsafe block. MoveTraversalImpl is also a very good point.

Comment addressed.

@@ -1529,6 +1529,11 @@ pub struct IterMut<'a, T:'a> {
}

#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<'a, T: Send+'a> Send for IterMut<'a, T> { }
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<'a, T: Sync+'a> Sync for IterMut<'a, T> { }
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps this could store Unique<T> instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done and then I tweaked the implementation to match Iter, which kills pointer all together.

Copy link
Member

Choose a reason for hiding this comment

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

These unsafe impl blocks can be removed now, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Indeed.

@edwardw
Copy link
Contributor Author

edwardw commented Feb 24, 2015

r? @alexcrichton

@rust-highfive rust-highfive assigned alexcrichton and unassigned huonw Feb 24, 2015

unsafe {
Some(&mut *self.ptr.offset(tail as isize))
let elem = self.ring.get_unchecked_mut(tail);
Some(mem::transmute(elem))
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 we tend to prefer avoiding transmute wherever possible, could this be written as Some(&mut *(elem as *mut _))?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@alexcrichton
Copy link
Member

Can you also add some tests to ensure that we don't regress in these aspects?

@edwardw
Copy link
Contributor Author

edwardw commented Feb 25, 2015

Hmm, seems I've tackled problem the wrong way. Test-driven would be better here. Will rework the patch.

@edwardw
Copy link
Contributor Author

edwardw commented Feb 25, 2015

An extensive test was added. r? @alexcrichton @huonw

@@ -568,6 +568,9 @@ pub struct Iter <'a, T: 'a> {
iter: slice::Iter<'a, T>,
}

unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't these be unnecessary? I would figure that slice::Iter would implement these as appropriate

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently it isn't. This can be removed, however, after libcore is properly Sync and Send audited. A FIXME maybe?

@alexcrichton
Copy link
Member

Nice test! Sorry for being so pedantic about these, but this feels like an extra level of unsafety I want to be sure we tread carefully with. To me there are a bunch more unsafe impl blocks than I would have expected originally. I would consider something like the following steps for considering whether to mark something with unsafe impl:

  1. Are there any interior unsafe pointers or UnsafeCell types? If not, then the problem lies in the constituent types, not at the top-level.
  2. Can any unsafe pointers be represented by other abstractions? For example Unique is one but there may be other helper structs as well.

Along those lines, some of the structures marked with unsafe impl fall into (1) where they don't contain unsafe things and the problem seems to lie in the underlying abstractions. I think we already got all the instances of (2).

Does that make sense?

@alexcrichton
Copy link
Member

@edwardw ah it seems you responded as I was responding! Would it be possible to go ahead and "audit" the relevant portions of libcore ahead of time? It should just involve dealing with slice::Iter for now (you don't have to do the whole audit of course). It's generally preferable to not have an intermediate state where lots of stuff is "slated for deletion"

@edwardw
Copy link
Contributor Author

edwardw commented Feb 25, 2015

Certainly. That leaves only RawItems business. I'll wait Mr. @gankro to confirm that one.

So it is symmetric to its `Iter` implementation. Also kills an FIXME.
@@ -740,6 +740,9 @@ pub struct Iter<'a, T: 'a> {
_marker: marker::PhantomData<&'a T>,
}

unsafe impl<'a, T: Sync> Sync for Iter<'a, T> {}
unsafe impl<'a, T: Sync> Send for Iter<'a, T> {}
Copy link
Member

Choose a reason for hiding this comment

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

T: Sync => T: Send

Copy link
Member

Choose a reason for hiding this comment

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

Sync is correct; Iter<T> is essentially the same as &T.

Copy link
Member

Choose a reason for hiding this comment

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

Oh wow that is subtle, looks like I should read this again.

In the process, also replaces a raw mutable pointers with Unique to
spell out the ownership semantics.

cc rust-lang#22709
@alexcrichton
Copy link
Member

@bors: r+ 6849006

@bors
Copy link
Contributor

bors commented Feb 26, 2015

⌛ Testing commit 6849006 with merge a5214e4...

bors added a commit that referenced this pull request Feb 26, 2015
In the process, also replaces two raw mutable pointers with `Unique` to
spell out the ownership semantics.

cc #22709
@bors bors merged commit 6849006 into rust-lang:master Feb 26, 2015
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.

None yet

7 participants