]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-146205: Check the errno with != 0 in close impls in select module (#146206)
authorAN Long <aisk@users.noreply.github.com>
Fri, 20 Mar 2026 13:44:01 +0000 (21:44 +0800)
committerGitHub <noreply@github.com>
Fri, 20 Mar 2026 13:44:01 +0000 (14:44 +0100)
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Lib/test/test_devpoll.py
Lib/test/test_epoll.py
Lib/test/test_kqueue.py
Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-12-52-55.gh-issue-146205.M4yKdf.rst [new file with mode: 0644]
Modules/selectmodule.c

index 85e0accb611b1d7a8775e1ed3f93356ed04e11d0..5951f8817ab1c11938d9085855daa31088aa0f85 100644 (file)
@@ -2,6 +2,7 @@
 
 # Initial tests are copied as is from "test_poll.py"
 
+import errno
 import os
 import random
 import select
@@ -112,6 +113,15 @@ class DevPollTests(unittest.TestCase):
         self.assertRaises(ValueError, devpoll.register, fd, select.POLLIN)
         self.assertRaises(ValueError, devpoll.unregister, fd)
 
+    def test_close_error(self):
+        # gh-146205: close() should raise OSError if underlying fd is invalid
+        devpoll = select.devpoll()
+        fd = devpoll.fileno()
+        os.close(fd)
+        with self.assertRaises(OSError) as cm:
+            devpoll.close()
+        self.assertEqual(cm.exception.errno, errno.EBADF)
+
     def test_fd_non_inheritable(self):
         devpoll = select.devpoll()
         self.addCleanup(devpoll.close)
index c94946a6ae6b7c3cff93f9d16c9fa19e4750b274..5e6a4ab0166a86ff10d88c11f684dc7afdc049ec 100644 (file)
@@ -259,6 +259,15 @@ class TestEPoll(unittest.TestCase):
         self.assertRaises(ValueError, epoll.register, fd, select.EPOLLIN)
         self.assertRaises(ValueError, epoll.unregister, fd)
 
+    def test_close_error(self):
+        # gh-146205: close() should raise OSError if underlying fd is invalid
+        epoll = select.epoll()
+        fd = epoll.fileno()
+        os.close(fd)
+        with self.assertRaises(OSError) as cm:
+            epoll.close()
+        self.assertEqual(cm.exception.errno, errno.EBADF)
+
     def test_fd_non_inheritable(self):
         epoll = select.epoll()
         self.addCleanup(epoll.close)
index d2ab45c4a5b1ea6bc6842ccad99477268bf4be15..2cf99be9e2c3baa3eaa7020a59846517772d5523 100644 (file)
@@ -254,6 +254,15 @@ class TestKQueue(unittest.TestCase):
         # operations must fail with ValueError("I/O operation on closed ...")
         self.assertRaises(ValueError, kqueue.control, None, 4)
 
+    def test_close_error(self):
+        # gh-146205: close() should raise OSError if underlying fd is invalid
+        kqueue = select.kqueue()
+        fd = kqueue.fileno()
+        os.close(fd)
+        with self.assertRaises(OSError) as cm:
+            kqueue.close()
+        self.assertEqual(cm.exception.errno, errno.EBADF)
+
     def test_fd_non_inheritable(self):
         kqueue = select.kqueue()
         self.addCleanup(kqueue.close)
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-12-52-55.gh-issue-146205.M4yKdf.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-20-12-52-55.gh-issue-146205.M4yKdf.rst
new file mode 100644 (file)
index 0000000..e9d95cd
--- /dev/null
@@ -0,0 +1,2 @@
+Fixed a bug where :meth:`select.epoll.close`, :meth:`select.kqueue.close`,\r
+and :meth:`select.devpoll.close` silently ignored errors.
index 137bf2ca55bbf82a2de0aa3a4a46e5bcd1fa88d6..4dd544c6ee8d34027bf76b7e69814a619e124f39 100644 (file)
@@ -1118,8 +1118,9 @@ static PyObject *
 select_devpoll_close_impl(devpollObject *self)
 /*[clinic end generated code: output=26b355bd6429f21b input=408fde21a377ccfb]*/
 {
-    errno = devpoll_internal_close(self);
-    if (errno < 0) {
+    int err = devpoll_internal_close(self);
+    if (err != 0) {
+        errno = err;
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
@@ -1446,8 +1447,9 @@ static PyObject *
 select_epoll_close_impl(pyEpoll_Object *self)
 /*[clinic end generated code: output=ee2144c446a1a435 input=f626a769192e1dbe]*/
 {
-    errno = pyepoll_internal_close(self);
-    if (errno < 0) {
+    int err = pyepoll_internal_close(self);
+    if (err != 0) {
+        errno = err;
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }
@@ -2263,8 +2265,9 @@ static PyObject *
 select_kqueue_close_impl(kqueue_queue_Object *self)
 /*[clinic end generated code: output=d1c7df0b407a4bc1 input=6d763c858b17b690]*/
 {
-    errno = kqueue_queue_internal_close(self);
-    if (errno < 0) {
+    int err = kqueue_queue_internal_close(self);
+    if (err != 0) {
+        errno = err;
         PyErr_SetFromErrno(PyExc_OSError);
         return NULL;
     }