Skip to content

Commit b32826b

Browse files
authored
runtime: fix leaking registration entries when os registration fails (#6329)
1 parent 2ce1cee commit b32826b

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

tokio/src/runtime/io/driver.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,8 +220,17 @@ impl Handle {
220220
let scheduled_io = self.registrations.allocate(&mut self.synced.lock())?;
221221
let token = scheduled_io.token();
222222

223-
// TODO: if this returns an err, the `ScheduledIo` leaks...
224-
self.registry.register(source, token, interest.to_mio())?;
223+
// we should remove the `scheduled_io` from the `registrations` set if registering
224+
// the `source` with the OS fails. Otherwise it will leak the `scheduled_io`.
225+
if let Err(e) = self.registry.register(source, token, interest.to_mio()) {
226+
// safety: `scheduled_io` is part of the `registrations` set.
227+
unsafe {
228+
self.registrations
229+
.remove(&mut self.synced.lock(), &scheduled_io)
230+
};
231+
232+
return Err(e);
233+
}
225234

226235
// TODO: move this logic to `RegistrationSet` and use a `CountedLinkedList`
227236
self.metrics.incr_fd_count();

tokio/src/runtime/io/registration_set.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,21 @@ impl RegistrationSet {
102102
}
103103

104104
pub(super) fn release(&self, synced: &mut Synced) {
105-
for io in synced.pending_release.drain(..) {
105+
let pending = std::mem::take(&mut synced.pending_release);
106+
107+
for io in pending {
106108
// safety: the registration is part of our list
107-
let _ = unsafe { synced.registrations.remove(io.as_ref().into()) };
109+
unsafe { self.remove(synced, io.as_ref()) }
108110
}
109111

110112
self.num_pending_release.store(0, Release);
111113
}
114+
115+
// This function is marked as unsafe, because the caller must make sure that
116+
// `io` is part of the registration set.
117+
pub(super) unsafe fn remove(&self, synced: &mut Synced, io: &ScheduledIo) {
118+
let _ = synced.registrations.remove(io.into());
119+
}
112120
}
113121

114122
// Safety: `Arc` pins the inner data

0 commit comments

Comments
 (0)