diff --git a/Kernel/Syscalls/poll.cpp b/Kernel/Syscalls/poll.cpp index c0a08c484f..940719af94 100644 --- a/Kernel/Syscalls/poll.cpp +++ b/Kernel/Syscalls/poll.cpp @@ -50,7 +50,10 @@ ErrorOr Process::sys$poll(Userspace use TRY(m_fds.with_shared([&](auto& fds) -> ErrorOr { for (size_t i = 0; i < params.nfds; i++) { auto& pfd = fds_copy[i]; - auto description = TRY(fds.open_file_description(pfd.fd)); + RefPtr description; + auto description_or_error = fds.open_file_description(pfd.fd); + if (!description_or_error.is_error()) + description = description_or_error.release_value(); BlockFlags block_flags = BlockFlags::WriteError | BlockFlags::WriteHangUp; // always want POLLERR, POLLHUP, POLLNVAL if (pfd.events & POLLIN) block_flags |= BlockFlags::Read; @@ -93,11 +96,13 @@ ErrorOr Process::sys$poll(Userspace use if (fds_entry.unblocked_flags == BlockFlags::None) continue; - if (has_any_flag(fds_entry.unblocked_flags, BlockFlags::WriteError | BlockFlags::WriteHangUp)) { + if (has_any_flag(fds_entry.unblocked_flags, BlockFlags::WriteError | BlockFlags::WriteHangUp) || !fds_entry.description) { if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteError)) pfd.revents |= POLLERR; if (has_flag(fds_entry.unblocked_flags, BlockFlags::WriteHangUp)) pfd.revents |= POLLHUP; + if (!fds_entry.description) + pfd.revents |= POLLNVAL; } else { if (has_flag(fds_entry.unblocked_flags, BlockFlags::Read)) { VERIFY(pfd.events & POLLIN); diff --git a/Kernel/Thread.h b/Kernel/Thread.h index b94bb22661..20f2c921a6 100644 --- a/Kernel/Thread.h +++ b/Kernel/Thread.h @@ -668,7 +668,7 @@ public: class SelectBlocker final : public FileBlocker { public: struct FDInfo { - NonnullRefPtr description; + RefPtr description; BlockFlags block_flags { BlockFlags::None }; BlockFlags unblocked_flags { BlockFlags::None }; }; diff --git a/Kernel/ThreadBlockers.cpp b/Kernel/ThreadBlockers.cpp index 5ef3924315..f510218576 100644 --- a/Kernel/ThreadBlockers.cpp +++ b/Kernel/ThreadBlockers.cpp @@ -360,6 +360,10 @@ bool Thread::SelectBlocker::setup_blocker() if (!should_block) continue; + if (!fd_entry.description) { + should_block = false; + continue; + } if (!fd_entry.description->blocker_set().add_blocker(*this, &fd_entry)) should_block = false; } @@ -371,8 +375,10 @@ Thread::SelectBlocker::~SelectBlocker() = default; void Thread::SelectBlocker::finalize() { Thread::FileBlocker::finalize(); - for (auto& fd_entry : m_fds) - fd_entry.description->blocker_set().remove_blocker(*this); + for (auto& fd_entry : m_fds) { + if (fd_entry.description) + fd_entry.description->blocker_set().remove_blocker(*this); + } } void Thread::SelectBlocker::will_unblock_immediately_without_blocking(UnblockImmediatelyReason reason) @@ -397,6 +403,7 @@ bool Thread::SelectBlocker::unblock_if_conditions_are_met(bool from_add_blocker, if (m_did_unblock) return false; + VERIFY(fd_info.description); auto unblock_flags = fd_info.description->should_unblock(fd_info.block_flags); if (unblock_flags == BlockFlags::None) return false; @@ -421,6 +428,11 @@ size_t Thread::SelectBlocker::collect_unblocked_flags() for (auto& fd_entry : m_fds) { VERIFY(fd_entry.block_flags != FileBlocker::BlockFlags::None); + if (!fd_entry.description) { + count++; + continue; + } + // unblock will have set at least the first descriptor's unblock // flags that triggered the unblock. Make sure we don't discard that // information as it may have changed by now!