-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
net: warn on creating a tokio socket from a blocking one #7166
base: master
Are you sure you want to change the base?
Conversation
See #5595. This adds a warning when constructing a tokio socket object from an underlying std socket that is not set to nonblocking mode. This warning is likely to incrementally turn into a hard error in the future.
Windows does not support this, so it only works on unix for now. |
let sock = socket2::SockRef::from(s); | ||
|
||
if !sock.nonblocking()? { | ||
eprintln!("Warning: registering a blocking socket, this may be a bug!"); |
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.
Is it possible/likely that users are already using stderr for other things? Emitting stderr from within a library feels kinda gross; it might be easier to spot if we just panic here.
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 actually feel similarly, the request to do it this way specifically came from @carllerche.
I'll leave it up to him to voice why he wants this approach.
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 spent some more time thinking about this question. I think that I am OK starting with a debug_assert
. I would like there to be a way to disable the assertion (in case a user has a legitimate case) , and the panic message links to an issue for the user to find out how to disable the panic and report their legitimate use case.
To disable the panic, we can use a tokio_allow_from_blocking_fd
cfg
flag or something similar. The linked issue can include steps for setting it.
cc/ @Darksonn wdyt?
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.
Using a debug assertion with a --cfg
to disable it seems preferable to the eprintln!
.
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.
Thanks for getting this to move forward!
Is from_std_set_nonblocking
/from_std_assume_nonblocking
still the long term plan?
Or will it instead be something where tokio sets it to nonblocking, like axum_server currently does?
Or will the panic be considered to be enough?
I think there's a bit that needs figured out still about what we do going forward. The trouble with the prior suggestion is that we actually still have the issue of I think our two long-term options here are going to be to either panic, or set the socket option silently, and there's good arguments to be made for both. There should also be something along the lines of Given that we either need to leave the footgun in |
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.
This also needs review from Carl before it can be merged.
#[cfg(feature = "net")] | ||
pub(crate) mod blocking_check; |
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.
Consider re-exporting check_socket_for_blocking
here to make the imports more nice.
let sock = socket2::SockRef::from(s); | ||
|
||
if !sock.nonblocking()? { | ||
eprintln!("Warning: registering a blocking socket, this may be a bug!"); |
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 warning should say that it comes from Tokio. Perhaps include Location::caller
via #[track_caller]
to print the caller location.
@@ -209,6 +210,8 @@ impl TcpListener { | |||
/// will block the thread, which will cause unexpected behavior. | |||
/// Non-blocking mode can be set using [`set_nonblocking`]. | |||
/// | |||
/// Tokio's handling of blocking sockets may change in the future. |
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 we improve this wording? I don't think it very clearly explains the situation. You could say something along the lines of "Passing a listener in blocking mode is always errornous, and the behavior in that case may change in the future. For example, it could panic."
|
||
#[cfg(unix)] | ||
#[allow(unused_variables)] | ||
pub(crate) fn check_socket_for_blocking<S: AsFd>(s: &S) -> crate::io::Result<()> { |
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 does this return io::Result
? It doesn't seem like the fn needs a return argument.
@@ -5,6 +5,7 @@ cfg_not_wasi! { | |||
use crate::net::{to_socket_addrs, ToSocketAddrs}; | |||
} | |||
|
|||
use crate::util::blocking_check::check_socket_for_blocking; |
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.
Very minor and not a needed change to merge, but IMO this check makes more sense in the net
module.
let sock = socket2::SockRef::from(s); | ||
|
||
if !sock.nonblocking()? { | ||
eprintln!("Warning: registering a blocking socket, this may be a bug!"); |
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 spent some more time thinking about this question. I think that I am OK starting with a debug_assert
. I would like there to be a way to disable the assertion (in case a user has a legitimate case) , and the panic message links to an issue for the user to find out how to disable the panic and report their legitimate use case.
To disable the panic, we can use a tokio_allow_from_blocking_fd
cfg
flag or something similar. The linked issue can include steps for setting it.
cc/ @Darksonn wdyt?
See #5595 and #7172.
This adds a warning when constructing a tokio socket object from an underlying std socket that is not set to nonblocking mode.
This warning is likely to incrementally turn into a hard error in the future.