Skip to content
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

Merged
merged 2 commits into from
Dec 2, 2017

Conversation

Susurrus
Copy link
Contributor

@Susurrus Susurrus commented Dec 1, 2017

Seems to have occurred within a Rust release after 1.13, so let's test all of them since then!

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 1, 2017

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.

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 1, 2017

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.

@Arnavion
Copy link
Contributor

Arnavion commented Dec 1, 2017

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]

@Susurrus Susurrus force-pushed the test_epoll branch 2 times, most recently from b066240 to 329eaa5 Compare December 1, 2017 06:19
@Susurrus Susurrus changed the title Test epoll bug Fix epoll bug in release mode on Rust 1.20+ Dec 1, 2017
@Susurrus Susurrus mentioned this pull request Dec 1, 2017
@Susurrus Susurrus requested a review from asomers December 1, 2017 06:45
@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 1, 2017

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?

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 1, 2017

Alright, we're all green here. @asomers If I don't hear back from you, I'll push this tonight.

Bryant Mairs added 2 commits December 1, 2017 10:55
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.
@asomers
Copy link
Member

asomers commented Dec 1, 2017

Awesome that you fixed it! Still, I don't fully understand why the old code failed. Was the problem that event.into() as *const EpollEvent == ptr::null() would always evaluate false, even when event was None, because the behavior of &mut *ptr::null_mut::<T> is undefined?

@Arnavion
Copy link
Contributor

Arnavion commented Dec 1, 2017

because the behavior of &mut *ptr::null_mut::<T> is undefined?

Yes. *ptr::null_mut() is UB.

@asomers
Copy link
Member

asomers commented Dec 1, 2017

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+

bors bot added a commit that referenced this pull request Dec 1, 2017
805: Fix epoll bug in release mode on Rust 1.20+ r=asomers a=Susurrus

Seems to have occurred within a Rust release after 1.13, so let's test all of them since then!
@bors
Copy link
Contributor

bors bot commented Dec 2, 2017

Timed out

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 2, 2017

bors retry

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 2, 2017

Guess that doesn't work.

bors r+ asomers

bors bot added a commit that referenced this pull request Dec 2, 2017
805: Fix epoll bug in release mode on Rust 1.20+ r=Susurrus a=Susurrus

Seems to have occurred within a Rust release after 1.13, so let's test all of them since then!
@bors
Copy link
Contributor

bors bot commented Dec 2, 2017

Timed out

@Susurrus
Copy link
Contributor Author

Susurrus commented Dec 2, 2017

Ugh!

bors r+

bors bot added a commit that referenced this pull request Dec 2, 2017
805: Fix epoll bug in release mode on Rust 1.20+ r=Susurrus a=Susurrus

Seems to have occurred within a Rust release after 1.13, so let's test all of them since then!
@bors
Copy link
Contributor

bors bot commented Dec 2, 2017

@bors bors bot merged commit 54313a7 into nix-rust:master Dec 2, 2017
@Susurrus Susurrus deleted the test_epoll branch December 2, 2017 16:42
@jonhoo
Copy link

jonhoo commented Jan 17, 2018

This changes the epoll API, so should probably be added to the changelog, no?

@Susurrus
Copy link
Contributor Author

@jonhoo This didn't change the API for epoll_ctl at all. You can see there was no test code changed in this PR, and there are at least 4 calls to epoll_ctl under /test. Technically it changed the API for &EpollEvent, but that is likely unused outside of the function call for this function, so I don't think it's worth mentioning.

@jonhoo
Copy link

jonhoo commented Jan 17, 2018

Ahh, specifically because Option<T>: From<T> -- got it!

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.

4 participants