-
Notifications
You must be signed in to change notification settings - Fork 67
refactor sock_ctrl_msg.rs for code clarity #246
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
Conversation
9337b2d to
042c82f
Compare
08cf044 to
0f76eb7
Compare
3057eec to
009475c
Compare
stefano-garzarella
left a comment
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.
LGTM! Thanks for this!
@roypat Have you had a chance to test it on macOS?
I've only build-tested it via cargo check for the mac target. @ShadowCurse when you come back from PTO, can you give this a try locally on your Mac to make sure I didn't break anything? :o |
I can try it too on my wife mac (I used it to debug the issue). @uran0sH can you also give this a try? |
|
On main: On this branch: I used |
Thanks for testing! huh, I wonder if that's 1b8d717, e.g. Mac doesn't set CMSG_TRUNC if the buffer for control data is empty? Can you adjust the loop in the failing test to start at 1, to see if those cases work at least? If they still fail, I guess that means CMSG_TRUNC isn't set at all by Mac? 🤔 Maybe that's why it set cmsg->len to such a weird value (and the |
|
@roypat yeah, with this change tests passes: diff --git a/src/unix/sock_ctrl_msg.rs b/src/unix/sock_ctrl_msg.rs
index 291de71..6881bff 100644
--- a/src/unix/sock_ctrl_msg.rs
+++ b/src/unix/sock_ctrl_msg.rs
@@ -505,7 +505,7 @@ mod tests {
// Exercise the code paths that activate the issue of receiving the all the ancillary data,
// but missing to provide enough buffer space to store it.
fn send_more_recv_less1() {
- for too_small in 0..3 {
+ for too_small in 1..3 {
let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");
let (_, evt_notifier1) = pipe().expect("failed to create pipe"); |
ugh, okaaay, so that just works differently on Mac and Linux then. What about the below? diff --git a/src/unix/sock_ctrl_msg.rs b/src/unix/sock_ctrl_msg.rs
index 291de71dc837..f102ec87ee84 100644
--- a/src/unix/sock_ctrl_msg.rs
+++ b/src/unix/sock_ctrl_msg.rs
@@ -202,13 +202,13 @@ unsafe fn raw_recvmsg(
// the cmsg->len field to the untruncated length of the message sent,
// even if the buffer is actually smaller. Compensate for this by reducing
// the length to be at most the size of the memory we have allocated.
+ teardown_control_data |= cmsg.len() > in_fds.len();
unsafe { cmsg.set_len(cmsg.len().min(cmsg_capacity)) }
let fds = cmsg.as_slice();
// It could be that while constructing the cmsg structures, alignment constraints made
// our allocation big enough that it fits more than the in_fds.len() file descriptors
// we intended to receive. Treat this the same way we would treat a truncated message,
// because there is no way for us to communicate these extra FDs back to the caller.
- teardown_control_data |= fds.len() > in_fds.len();
if teardown_control_data {
for fd in fds {
libc::close(*fd);(and having the test back to starting the loop at 0) |
|
@roypat nope, same issue as #246 (comment) |
We had two test cases that only different by the value of a single constant. Merge these two cases into a single case that iterates over all possible constants that will fulfill the test assertions (e.g. all buffer sizes that are too small for 4 file descriptors). Don't cover too_small = 0 for now, as due to a bug in raw_recvmsg(), we dont actually handle CMSG_TRUNC if in_fds is empty, so this test case would currently incorrectly pass. While we're here, replace assert!((...).is_err()) with .unwrap_err() so that in case the test fails we get a meaningful error message. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
6f63130 to
88032cc
Compare
Alright, in that case, I think the only thing we can do is adjust the test to not do the "in buffer size == 0" thing, and just say it works differently on linux and mac :( |
Currently, if in_fds.len() == 0, but the kernel has some control data to read, raw_recvmsg() returns Ok((_, 0)), despite CMSG_TRUNC being set. Return ENOBUFS instead, as would be the case if in_fds.len() > 0 yet smaller than the number of fds the kernel has for us. Simply removing the early-return is correct, as the only way to msg_controllen to be less than sizeof::<cmsghdr>() is when the kernel has zeroed it out because no control data was available, or because it was zero all along because in_fds.len() == 0. In both cases, cmsg_ptr.is_null() will be true, we skip over the loop, and the final return will end up being Ok((_, 0)). Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
raw_recvmsg implemented a loop to be able to process arbitrary control message chains. However, in this specific function, we know exactly what the control message chain looks like, because we construct it ourselves. It always consists of a single cmsghdr structure. So remove all the code related to processing different layouts. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
cmsghdr is a fam struct with some additional alignment constraints for the flexible array member, so we can use the machinery in fam.rs to deal with it. This comes with the benefit of a _lot_ less unsafe code. It removes an optimization where sometimes cmsghdr structures were allocated on the stack if the number of fds to receive was small enough, but raw_recvmsg was already allocating on the heap for the iovecs anyway, so this optimization seems a bit pre-mature. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
88032cc to
b73a9fd
Compare
stefano-garzarella
left a comment
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.
Tests passed on macOS!
Summary of the PR
During the review of #245 we identified various opportunities for simplifying the sock_ctrl_msg.rs code and tests. This PR first unifies some tests and fixes a bug where CMSG_TRUNC wasn't properly handled if the given slice of RawFds to receive was empty. Then, simplify code for parsing arbitrary cmsg(3) structures, as this is not actually needed (the library constructs the msghdr itself, and thus knows exactly the layout of the contained cmsghdr structs). Lastly, switch over to treating cmsghdr as fam.rs
FamStructs, to remove a ton of unsafe code that was used to do an ad-hoc re-implementation of fam struct handling.Requirements
Before submitting your PR, please make sure you addressed the following
requirements:
git commit -s), and the commit message has max 60 characters for thesummary and max 75 characters for each description line.
test.
Release" section of CHANGELOG.md (if no such section exists, please create one).
unsafecode is properly documented.