Skip to content

Conversation

pacak
Copy link
Contributor

@pacak pacak commented Oct 30, 2024

The msg_name field points to a caller-allocated buffer that is used to return the source address if the socket is unconnected. The caller should set msg_namelen to the size of this buffer before this call; upon return from a successful call, msg_namelen will contain the length of the returned address. If the application does not need to know the source address, msg_name can be specified as NULL.

In case we use () msgname_len gets initialized with 0, but pointer to the array with msg_name. This works for the first iteration somehow, but after that kernel sets msgname_len to a non-zero and second invocation with the same MultiHeader fails

What does this PR do

Fixes #2506

Checklist:

  • I have read CONTRIBUTING.md
  • I have written necessary tests and rustdoc comments
  • A change log has been added if this PR modifies nix's API

let p = mhdr.as_mut_ptr();
unsafe {
(*p).msg_name = address as *mut c_void;
(*p).msg_name = if S::size() == 0 { ptr::null_mut() } else { (*address).as_mut_ptr() as *mut c_void };
Copy link
Member

Choose a reason for hiding this comment

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

(*address).as_mut_ptr() as *mut c_void

Any idea why it would work after reverting the change made in #2041?

Copy link
Member

@SteveLauC SteveLauC Oct 31, 2024

Choose a reason for hiding this comment

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

not sure if things fixed by https://github.com/nix-rust/nix/pull/2041 are still working after that.

Considering this, gentle ping on @JarredAllen, the author of #2041, could you please take a look at this PR?

Context

@pacak is trying to solve #2506, after digging into the previous Nix versions(Thank you for this!), he figured out that the issue is possibly introduced by #2041:

Screenshot 2024-10-31 at 8 33 28 AM

If we can have you, I hope we can solve the following questions:

  1. The reason behind above change made in Set the length of a socket address when calling recvmsg on Linux #2041, and possibly why reverting it would fix Re-use MultiHeader<()> in subsequent recvmmsg() calls #2506.
  2. The things that Set the length of a socket address when calling recvmsg on Linux #2041 tried to fix would still work after this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any idea why it would work after reverting the change made in #2041?

As far as I understand .as_mut_ptr() gives a null pointer in case of (), address as *mut c_void gives a dangling pointer through magic of rustc optimizations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess just using .as_mut_ptr() would be enough as long as all the instances return the right pointer. Explicit checking for size makes it so it works even if there's a bogus instance.

Copy link
Member

Choose a reason for hiding this comment

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

As far as I understand .as_mut_ptr() gives a null pointer in case of (), address as *mut c_void gives a dangling pointer through magic of rustc optimizations.

If so

I guess just using .as_mut_ptr() would be enough as long as all the instances return the right pointer.

then yes


not sure if things fixed by #2041 are still working after that.

I think this PR won't break the fix done by #2041 as there is a unit test guarding it.

BTW, let's document why we should use .as_mut_tr() rather than address as *mut c_void because it is so easy to revert the fix if one is not aware of such a subtle different behavior . 😮‍💨

Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry I wasn't around, but thanks for fixing my mistake! I concur with the assessment that this shouldn't break my fix.

Copy link
Member

Choose a reason for hiding this comment

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

No need to be sorry. 😆

pacak added 2 commits November 2, 2024 06:38
The msg_name field points to a caller-allocated buffer that is used to
return the source address if the socket is unconnected. The caller
should set msg_namelen to the size of this buffer before this call; upon
return from a successful call, msg_namelen will contain the length of
the returned address. If the application does not need to know the
source address, msg_name can be specified as NULL.

In case we use () msgname_len gets initialized with 0, but a dangling
pointer to the array with msg_name. This works for the first iteration
somehow, but after that kernel sets msgname_len to a non-zero and second
invocation with the same MultiHeader fails

Fixes nix-rust#2506
Copy link
Member

@SteveLauC SteveLauC left a comment

Choose a reason for hiding this comment

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

Thanks! Appreciate the patience when you struggle with the format.

@SteveLauC SteveLauC added this pull request to the merge queue Nov 3, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 3, 2024
@SteveLauC SteveLauC added this pull request to the merge queue Nov 3, 2024
Merged via the queue into nix-rust:master with commit 5fe8266 Nov 3, 2024
39 checks passed
@pacak pacak deleted the recvmmsg branch February 9, 2025 23:30
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.

Re-use MultiHeader<()> in subsequent recvmmsg() calls

3 participants