Skip to content

Commit 143710f

Browse files
committed
Tokio ICE fix: Changed the type of EpollEventInterest::epfd from i32 to WeakFileDescriptionRef
1 parent 7d8ee71 commit 143710f

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

Diff for: src/tools/miri/src/shims/unix/linux/epoll.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ impl EpollEventInstance {
5151
#[derive(Clone, Debug)]
5252
pub struct EpollEventInterest {
5353
/// The file descriptor value of the file description registered.
54+
/// This is only used for ready_list, to inform userspace which FD triggered an event.
55+
/// For that, it is crucial to preserve the original FD number.
56+
/// This FD number must never be "dereferenced" to a file description inside Miri.
5457
fd_num: i32,
5558
/// The events bitmask retrieved from `epoll_event`.
5659
events: u32,
@@ -61,8 +64,8 @@ pub struct EpollEventInterest {
6164
data: u64,
6265
/// Ready list of the epoll instance under which this EpollEventInterest is registered.
6366
ready_list: Rc<RefCell<BTreeMap<(FdId, i32), EpollEventInstance>>>,
64-
/// The file descriptor value that this EpollEventInterest is registered under.
65-
epfd_num: i32,
67+
/// The epoll file description that this EpollEventInterest is registered under.
68+
weak_epfd: WeakFileDescriptionRef,
6669
}
6770

6871
/// EpollReadyEvents reflects the readiness of a file description.
@@ -343,7 +346,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
343346
events,
344347
data,
345348
ready_list: Rc::clone(ready_list),
346-
epfd_num: epfd_value,
349+
weak_epfd: epfd.downgrade(),
347350
}));
348351

349352
if op == epoll_ctl_add {
@@ -553,12 +556,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
553556
if is_updated {
554557
// Edge-triggered notification only notify one thread even if there are
555558
// multiple threads block on the same epfd.
556-
let epfd = this.machine.fds.get(epoll_interest.borrow().epfd_num).unwrap();
557559

558560
// This unwrap can never fail because if the current epoll instance were
559-
// closed and its epfd value reused, the upgrade of weak_epoll_interest
561+
// closed, the upgrade of weak_epoll_interest
560562
// above would fail. This guarantee holds because only the epoll instance
561563
// holds a strong ref to epoll_interest.
564+
let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap();
562565
// FIXME: We can randomly pick a thread to unblock.
563566
if let Some(thread_id) =
564567
epfd.downcast::<Epoll>().unwrap().thread_id.borrow_mut().pop()

Diff for: src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs

+38
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ fn main() {
2323
test_ready_list_fetching_logic();
2424
test_epoll_ctl_epfd_equal_fd();
2525
test_epoll_ctl_notification();
26+
test_issue_3858();
2627
}
2728

2829
// Using `as` cast since `EPOLLET` wraps around
@@ -683,3 +684,40 @@ fn test_epoll_ctl_notification() {
683684
// for this epfd, because there is no I/O event between the two epoll_wait.
684685
check_epoll_wait::<1>(epfd0, &[]);
685686
}
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

Comments
 (0)