-
Notifications
You must be signed in to change notification settings - Fork 16
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
ReadHandle (and others) are unsound due to missing Send and Sync bounds #12
Comments
Yes, I think you're completely right! Would you mind filing a PR? |
Good news... I just downloaded the repository to check, and it seems like this issue is already partially fixed (for ReadGuard) in the latest (0.11) version (due to jonhoo/left-right#75 being fixed for left-right). However, it still has some safety issues since I think it missed the root cause, namely ReadHandleFactory has the same issue (and maybe other stuff). I'll submit a slightly cleaner fix for left-right to fix this for good, but I'm not totally sure how one would go about backporting this to 0.10, since there doesn't even appear to be a feature branch for it anymore (and you indicated you didn't feel like fixing this bug in 0.10 previously). Any suggestions? Is there a reason not to just make 0.11 the latest release and yank 0.10.x? |
There should be a tag for 0.10, so you should be able to branch off of that. That said, unless you have a desperate need, I'd like to just fix this for 0.11 — there are other things broken in 0.10, and there's no LTS guarantee, so fixing on the latest version seems fine to me. I think I'm also okay landing evmap 0.11 at this point (with said fix) 👍 And yes, a fix to left-right would be lovely! |
any 0.11 release coming soon? |
@joshuayanovski-okta did you ever get a chance to put together a PR to fix this in 0.11? @banacer There isn't a fix for this in the code base yet I don't think, but I'm happy to release 0.11 final once a fix lands! |
Unfortunately, due to an oversight,
Inner
doesn't inherit any requirements onSend
/Sync
to beSend / Sync
, soReadHandle
is unconditionallySend
. This is because AtomicPtr has no Send bound on itsT
(I understand why, because technically you can use it from safe code with a non-Send type), so the auto-Send/Sync bound didn't get applied for K, V, M, or S; but in practice, most unsafe code will actually dereference the pointer at some point so this is usually wrong in that case. It might be nice to have some on-by-default lint for use of AtomicPtr without manually checking the appropriate bounds).Just not having bounds on
Send
wouldn't necessarily makeReadHandle
unsound, but I believe it is.ReadHandle
effectively owns aMapReadRef
which is (AFAIK, correctly) onlySend
when K, V, M, and S areSync
(fortunately, I think they don't need to beSend
since you can't get an owned instance of any of those out of aMapReadRef
directly, so I believe that part is sound). SinceReadHandle
owns (and provides access to)MapReadRef
, it follows thatReadHandle: Send
should at least requireK, V, M, S : Sync
.There are a few other ways to access values of the generic types in question on
ReadHandle
besides via theMapReadRef
, but from what I saw none of them provide owned access to any of K, V, M, or S (at least, not owned access that calls any safe trait methods or hands them to the user, though maybe internally it does something like that), so I think just theSync
bound on the type parameters is also sufficient for safety ofReadHandle: Send
, notSend+Sync
on the type parameters, which is actually somewhat unusual for stuff like this (Sync
containing!Sync
is much more common thanSend
containing!Send
). The weak bounds are due (I think) to the fact that the reader types don't ever callDrop
on values of the owned type, only the writer type does, and there's nothing likeArc::make_mut
and friends, so evmap implements a "weaker" form of sharing thanArc
does.The unsoundness of at least one other type (
ReadHandleFactory
) follows from this same root cause of using anAtomicPtr
(arguably, it's worse, since it's not only unconditionallySend
but also unconditionallySync
) and needs to be fixed in the same way (Arc<T>
requiresT: Send+Sync
for bothSend
andSync
, and theAtomicPtr
is in anArc
, so you don't need to explicitlyimpl !Send
here).More subtly,
WriteHandle
is also unsound for the same reason (this should get fixed automatically ifReadHandle
is, since it owns aReadHandle
). At first, I actually thoughtWriteHandle
should be able to be made sound without changing itsSend
requirements from what they currently are (which would require an explicitSend
impl if theReadHandle
fix were added), because you can only write/drop through a uniqueWriteHandle
, and you can't write at the same time as theDeref
implementation onWriteHandle
is active. Unfortunately, (1) we always create a ReadHandle on startup for some reason (despite the fact that WriteHandle already owns one internally?), and (2) even if we didn't, theDeref
implementation onWriteHandle
lets you clone theReadHandle
(though (2) is technically solvable by putting the relevantSync
bounds on theDeref
implementation, or by not having theDeref
implementation and exposing access to the non-clone
/factory
methods via wrappers instead). SoWriteHandle
should really just inherit the extra bounds from its ownedReadHandle
.There are probably a few other other types with the same issue.
The text was updated successfully, but these errors were encountered: