-
Notifications
You must be signed in to change notification settings - Fork 672
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
Fix epoll bug in release mode on Rust 1.20+ #805
Conversation
Progress! Looks like epoll works before 1.20 and fails from then onwards. Nothing immediately sticks out to me in the release notes, gonna hop onto #rust and ask. |
This is the only thing that seems to be really fundamental that's changed. I'd prefer not to have to test Rust right before this merged and right after, but maybe that's the proper next step. |
diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs
index 5ab766d..69effe7 100644
--- a/src/sys/epoll.rs
+++ b/src/sys/epoll.rs
@@ -65,16 +65,6 @@ impl EpollEvent {
}
}
-impl<'a> Into<&'a mut EpollEvent> for Option<&'a mut EpollEvent> {
- #[inline]
- fn into(self) -> &'a mut EpollEvent {
- match self {
- Some(epoll_event) => epoll_event,
- None => unsafe { &mut *ptr::null_mut::<EpollEvent>() }
- }
- }
-}
-
#[inline]
pub fn epoll_create() -> Result<RawFd> {
let res = unsafe { libc::epoll_create(1024) };
@@ -91,15 +81,21 @@ pub fn epoll_create1(flags: EpollCreateFlags) -> Result<RawFd> {
#[inline]
pub fn epoll_ctl<'a, T>(epfd: RawFd, op: EpollOp, fd: RawFd, event: T) -> Result<()>
- where T: Into<&'a mut EpollEvent>
+ where T: Into<Option<&'a mut EpollEvent>>
{
- let event: &mut EpollEvent = event.into();
- if event as *const EpollEvent == ptr::null() && op != EpollOp::EpollCtlDel {
- Err(Error::Sys(Errno::EINVAL))
- } else {
- let res = unsafe { libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event) };
- Errno::result(res).map(drop)
- }
+ let mut event: Option<&mut EpollEvent> = event.into();
+ let res = unsafe {
+ if let Some(ref mut event) = event {
+ libc::epoll_ctl(epfd, op as c_int, fd, &mut event.event)
+ } else {
+ if op != EpollOp::EpollCtlDel {
+ return Err(Error::Sys(Errno::EINVAL));
+ }
+
+ libc::epoll_ctl(epfd, op as c_int, fd, ptr::null_mut())
+ }
+ };
+ Errno::result(res).map(drop)
}
#[inline] |
b066240
to
329eaa5
Compare
It's passed everything but Apple tests now because Travis is super backlogged. Hopefully it completes soon, but this should be GTG already. @asomers Care to give this a look-over? |
Alright, we're all green here. @asomers If I don't hear back from you, I'll push this tonight. |
When passing None as an argument to `epoll_ctl`, UB is elicited within the `Into<&EpollEvent>` impl because it passes a null pointer as a `&mut EpollEvent`. Instead we remove that implementation completely and handle this case directly within the `epoll_ctl` function. Thanks to Arnavion for helping to debug this.
Awesome that you fixed it! Still, I don't fully understand why the old code failed. Was the problem that |
Yes. |
Too bad the compiler can't detect that. Thanks for helping to fix it! We've known about this bug since the summer, but never understood what was going on. bors r+ |
Timed out |
bors retry |
Guess that doesn't work. bors r+ asomers |
Timed out |
Ugh! bors r+ |
This changes the epoll API, so should probably be added to the changelog, no? |
@jonhoo This didn't change the API for |
Ahh, specifically because |
Seems to have occurred within a Rust release after 1.13, so let's test all of them since then!