https://github.com/python/cpython/commit/64ff1e217d963b48140326e8b63c62f4b306f4a0
commit: 64ff1e217d963b48140326e8b63c62f4b306f4a0
branch: main
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2024-05-31T17:18:40+02:00
summary:

gh-119770: Make termios ioctl() constants positive (#119840)

files:
A Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst
M Lib/test/test_ioctl.py
M Lib/test/test_termios.py
M Modules/termios.c

diff --git a/Lib/test/test_ioctl.py b/Lib/test/test_ioctl.py
index 7b7067eb7b61d4..04934dfa16a5f0 100644
--- a/Lib/test/test_ioctl.py
+++ b/Lib/test/test_ioctl.py
@@ -66,23 +66,15 @@ def test_ioctl_mutate_2048(self):
         # Test with a larger buffer, just for the record.
         self._check_ioctl_mutate_len(2048)
 
-    def test_ioctl_signed_unsigned_code_param(self):
-        if not pty:
-            raise unittest.SkipTest('pty module required')
+    @unittest.skipIf(pty is None, 'pty module required')
+    def test_ioctl_set_window_size(self):
         mfd, sfd = pty.openpty()
         try:
-            if termios.TIOCSWINSZ < 0:
-                set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ
-                set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff
-            else:
-                set_winsz_opcode_pos = termios.TIOCSWINSZ
-                set_winsz_opcode_maybe_neg, = struct.unpack("i",
-                        struct.pack("I", termios.TIOCSWINSZ))
-
-            our_winsz = struct.pack("HHHH",80,25,0,0)
-            # test both with a positive and potentially negative ioctl code
-            new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz)
-            new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz)
+            # (rows, columns, xpixel, ypixel)
+            our_winsz = struct.pack("HHHH", 20, 40, 0, 0)
+            result = fcntl.ioctl(mfd, termios.TIOCSWINSZ, our_winsz)
+            new_winsz = struct.unpack("HHHH", result)
+            self.assertEqual(new_winsz[:2], (20, 40))
         finally:
             os.close(mfd)
             os.close(sfd)
diff --git a/Lib/test/test_termios.py b/Lib/test/test_termios.py
index 58698ffac2d981..22e397c7a409c4 100644
--- a/Lib/test/test_termios.py
+++ b/Lib/test/test_termios.py
@@ -211,6 +211,15 @@ def test_constants(self):
         self.assertLess(termios.VTIME, termios.NCCS)
         self.assertLess(termios.VMIN, termios.NCCS)
 
+    def test_ioctl_constants(self):
+        # gh-119770: ioctl() constants must be positive
+        for name in dir(termios):
+            if not name.startswith('TIO'):
+                continue
+            value = getattr(termios, name)
+            with self.subTest(name=name):
+                self.assertGreaterEqual(value, 0)
+
     def test_exception(self):
         self.assertTrue(issubclass(termios.error, Exception))
         self.assertFalse(issubclass(termios.error, OSError))
diff --git 
a/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst 
b/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst
new file mode 100644
index 00000000000000..94265e442db584
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-05-31-12-57-31.gh-issue-119770.NCtels.rst
@@ -0,0 +1 @@
+Make :mod:`termios` ``ioctl()`` constants positive. Patch by Victor Stinner.
diff --git a/Modules/termios.c b/Modules/termios.c
index 0633d8f82cc7e4..efb5fcc17fa5ef 100644
--- a/Modules/termios.c
+++ b/Modules/termios.c
@@ -1352,9 +1352,21 @@ termios_exec(PyObject *mod)
     }
 
     while (constant->name != NULL) {
-        if (PyModule_AddIntConstant(
-            mod, constant->name, constant->value) < 0) {
-            return -1;
+        if (strncmp(constant->name, "TIO", 3) == 0) {
+            // gh-119770: Convert value to unsigned int for ioctl() constants,
+            // constants can be negative on macOS whereas ioctl() expects an
+            // unsigned long 'request'.
+            unsigned int value = constant->value & UINT_MAX;
+            if (PyModule_Add(mod, constant->name,
+                             PyLong_FromUnsignedLong(value)) < 0) {
+                return -1;
+            }
+        }
+        else {
+            if (PyModule_AddIntConstant(
+                mod, constant->name, constant->value) < 0) {
+                return -1;
+            }
         }
         ++constant;
     }

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to