Skip to content

Commit 64ff1e2

Browse files
authored
gh-119770: Make termios ioctl() constants positive (#119840)
1 parent bcc1be3 commit 64ff1e2

File tree

4 files changed

+32
-18
lines changed

4 files changed

+32
-18
lines changed

Lib/test/test_ioctl.py

+7-15
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,15 @@ def test_ioctl_mutate_2048(self):
6666
# Test with a larger buffer, just for the record.
6767
self._check_ioctl_mutate_len(2048)
6868

69-
def test_ioctl_signed_unsigned_code_param(self):
70-
if not pty:
71-
raise unittest.SkipTest('pty module required')
69+
@unittest.skipIf(pty is None, 'pty module required')
70+
def test_ioctl_set_window_size(self):
7271
mfd, sfd = pty.openpty()
7372
try:
74-
if termios.TIOCSWINSZ < 0:
75-
set_winsz_opcode_maybe_neg = termios.TIOCSWINSZ
76-
set_winsz_opcode_pos = termios.TIOCSWINSZ & 0xffffffff
77-
else:
78-
set_winsz_opcode_pos = termios.TIOCSWINSZ
79-
set_winsz_opcode_maybe_neg, = struct.unpack("i",
80-
struct.pack("I", termios.TIOCSWINSZ))
81-
82-
our_winsz = struct.pack("HHHH",80,25,0,0)
83-
# test both with a positive and potentially negative ioctl code
84-
new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_pos, our_winsz)
85-
new_winsz = fcntl.ioctl(mfd, set_winsz_opcode_maybe_neg, our_winsz)
73+
# (rows, columns, xpixel, ypixel)
74+
our_winsz = struct.pack("HHHH", 20, 40, 0, 0)
75+
result = fcntl.ioctl(mfd, termios.TIOCSWINSZ, our_winsz)
76+
new_winsz = struct.unpack("HHHH", result)
77+
self.assertEqual(new_winsz[:2], (20, 40))
8678
finally:
8779
os.close(mfd)
8880
os.close(sfd)

Lib/test/test_termios.py

+9
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,15 @@ def test_constants(self):
211211
self.assertLess(termios.VTIME, termios.NCCS)
212212
self.assertLess(termios.VMIN, termios.NCCS)
213213

214+
def test_ioctl_constants(self):
215+
# gh-119770: ioctl() constants must be positive
216+
for name in dir(termios):
217+
if not name.startswith('TIO'):
218+
continue
219+
value = getattr(termios, name)
220+
with self.subTest(name=name):
221+
self.assertGreaterEqual(value, 0)
222+
214223
def test_exception(self):
215224
self.assertTrue(issubclass(termios.error, Exception))
216225
self.assertFalse(issubclass(termios.error, OSError))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Make :mod:`termios` ``ioctl()`` constants positive. Patch by Victor Stinner.

Modules/termios.c

+15-3
Original file line numberDiff line numberDiff line change
@@ -1352,9 +1352,21 @@ termios_exec(PyObject *mod)
13521352
}
13531353

13541354
while (constant->name != NULL) {
1355-
if (PyModule_AddIntConstant(
1356-
mod, constant->name, constant->value) < 0) {
1357-
return -1;
1355+
if (strncmp(constant->name, "TIO", 3) == 0) {
1356+
// gh-119770: Convert value to unsigned int for ioctl() constants,
1357+
// constants can be negative on macOS whereas ioctl() expects an
1358+
// unsigned long 'request'.
1359+
unsigned int value = constant->value & UINT_MAX;
1360+
if (PyModule_Add(mod, constant->name,
1361+
PyLong_FromUnsignedLong(value)) < 0) {
1362+
return -1;
1363+
}
1364+
}
1365+
else {
1366+
if (PyModule_AddIntConstant(
1367+
mod, constant->name, constant->value) < 0) {
1368+
return -1;
1369+
}
13581370
}
13591371
++constant;
13601372
}

0 commit comments

Comments
 (0)