-
Notifications
You must be signed in to change notification settings - Fork 674
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
Major cmsg cleanup #1020
Major cmsg cleanup #1020
Conversation
/// [`unix(7)`](http://man7.org/linux/man-pages/man7/unix.7.html) man page. | ||
// FIXME: When `#[repr(transparent)]` is stable, use it on `UnixCredentials` | ||
// and put that in here instead of a raw ucred. | ||
pub enum ControlMessageOwned { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per my previous comment, I think this is the wrong way to go, as it incurs avoidable heap allocation and copying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose to go this path because it's closer to backwards-compatible. I tried the 100% backwards-compatible method first, but the code got very ugly very quick, and it involved even more copying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems to be that you've settled on the worst of both worlds: both a breaking change and inefficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you suggest something more efficient that causes no more pain for existing users? This solution, while not exactly backwards compatible, only requires a simple search and replace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the current specific level of breakage makes sense as a line in the sand that cannot be crossed by a single step. That said, you could compromise by only using the flyweight pattern where heap allocation is otherwise necessary, i.e. in ScmRights
, though this would make "Owned" no longer an accurate descriptor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what's to say that ScmRights
's payload is aligned on all platforms that Nix will ever support? I don't think that's guaranteed, especially if a user ever passes an unaligned msg_control field to recvmsg.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's why I said "flyweight pattern" and not "a slice", yes. Refer to the comment I linked for an example implementation.
/// let _ = cmsg_space!(RawFd, TimeVal); | ||
/// ``` | ||
// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a | ||
// stack-allocated array. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be corrected? This seems like exactly the special case that const fns can already handle gracefully, and is the intended use of the C macros.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The libc people are resistant to that kind of change. rust-lang/libc#1213 (actually that's a separate issue). The cmsg functions can't be made const
because that requires rustc 1.31.0. libc guarantees support for 1.13.0.
/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message | ||
/// // and a `ControlMessageOwned::ScmTimestamp` message | ||
/// let _ = cmsg_space!(RawFd, TimeVal); | ||
/// ``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love this interface!
src/sys/socket/mod.rs
Outdated
// The number of bytes received. | ||
pub bytes: usize, | ||
cmsg_buffer: &'a [u8], | ||
cmsghdr: *const cmsghdr, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not a real reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because there are only three things we're going to do with that member. Pass it to CMSG_NXTHDR
and CMSG_DATA
, which expect pointere, and do some raw pointer arithmetic in decode_from
. So no sense converting it to a reference when we'd just have to convert it back again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
References can convert to pointers implicitly, and the PhantomData
would be rendered unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a matter of fact, this turned out to be pretty easy. I'll do it.
Thanks for your work on the libc macros, by the way! |
The QEMU failures are due to a bug in QEMU itself. For once I'm sure of it. The emulated recvmsg is writing beyond the end of the supplied msg_control buffer. I think it's probably due to the linked qemu bug, which is already fixed. I'll disable the test. Once japaric/cross updates its image to use qemu 2.12.0, then we can reenable it. |
Sigh. Travis got confused somehow and thinks I'm missing a merge commit. I guess I may as well rebase. |
55b67b0
to
55e28c7
Compare
I'm going to go ahead and merge this. @Ralith if you're still concerned, then please submit a separate PR to reduce data copies. |
2125d63
to
f11fe7f
Compare
bors r+ |
Merge conflict (retrying...) |
Merge conflict |
Our hand-rolled logic had subtle alignment bugs that caused test_scm_rights to fail on OpenBSD (and probably could cause problems on other platforms too). Using cmsg(3) is much cleaner, shorter, and more portable. No user-visible changes.
There were two problems: 1) It would always return Ok, even on error 2) It could panic if there was an error, because sockaddr_storage_to_addr would be called on uninitialized memory.
CmsgSpace had three problems: 1) It would oversize buffers that expect multiple control messages 2) It didn't use the libc CMSG_SPACE(3) macro, so it might actually undersize a buffer for a single control message. 3) It could do bad things on drop, if you instantiate it with a type that implements Drop (which none of the currently supported ControlMessage types do). Fixes nix-rust#994
On some platforms the alignment of cmsg_data could be less than the alignment of the messages that it contains. That led to unaligned reads on those platforms. This change fixes the issue by always copying the message contents into aligned objects. The change is not 100% backwards compatible when using recvmsg. Users may have to replace code like this: ```rust if let ControlMessage::ScmRights(&fds) = cmsg { ``` with this: ```rust if let ControlMessageOwned::ScmRights(fds) = cmsg { ``` Fixes nix-rust#999
This was an oversight from PR nix-rust#1002
bors r+ |
I don't actually use Nix at present, so I'm just going to stick with my current implementation that doesn't have these issues. |
Build succeeded
|
It was leftover from internal churn during PR nix-rust#1020.
It was leftover from internal churn during PR nix-rust#1020.
It was leftover from internal churn during PR nix-rust#1020.
This PR fixes multiple bugs in the cmsg code.
Fixes #994
Fixes #999
Fixes #1013