@@ -23,6 +23,7 @@ fn main() {
23
23
test_ready_list_fetching_logic();
24
24
test_epoll_ctl_epfd_equal_fd();
25
25
test_epoll_ctl_notification();
26
+ test_issue_3858();
26
27
}
27
28
28
29
// Using `as` cast since `EPOLLET` wraps around
@@ -683,3 +684,40 @@ fn test_epoll_ctl_notification() {
683
684
// for this epfd, because there is no I/O event between the two epoll_wait.
684
685
check_epoll_wait::<1>(epfd0, &[]);
685
686
}
687
+
688
+ // Test for ICE caused by weak epoll interest upgrade succeed, but the attempt to retrieve
689
+ // the epoll instance based on the epoll file descriptor value failed. EpollEventInterest
690
+ // should store a WeakFileDescriptionRef instead of the file descriptor number, so if the
691
+ // epoll instance is duped, it'd still be usable after `close` is called on the original
692
+ // epoll file descriptor.
693
+ // https://github.com/rust-lang/miri/issues/3858
694
+ fn test_issue_3858() {
695
+ // Create an eventfd instance.
696
+ let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC;
697
+ let fd = unsafe { libc::eventfd(0, flags) };
698
+
699
+ // Create an epoll instance.
700
+ let epfd = unsafe { libc::epoll_create1(0) };
701
+ assert_ne!(epfd, -1);
702
+
703
+ // Register eventfd with EPOLLIN | EPOLLET.
704
+ let mut ev = libc::epoll_event {
705
+ events: (libc::EPOLLIN | libc::EPOLLET) as _,
706
+ u64: u64::try_from(fd).unwrap(),
707
+ };
708
+ let res = unsafe { libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fd, &mut ev) };
709
+ assert_eq!(res, 0);
710
+
711
+ // Dup the epoll instance.
712
+ let newfd = unsafe { libc::dup(epfd) };
713
+ assert_ne!(newfd, -1);
714
+
715
+ // Close the old epoll instance, so the new FD is now the only FD.
716
+ let res = unsafe { libc::close(epfd) };
717
+ assert_eq!(res, 0);
718
+
719
+ // Write to the eventfd instance.
720
+ let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
721
+ let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
722
+ assert_eq!(res, 8);
723
+ }
0 commit comments