Skip to content

Commit 9300a59

Browse files
authored
gh-134744: Fix fcntl error handling (#134748)
Fix also reference leak on buffer overflow.
1 parent 176b059 commit 9300a59

File tree

3 files changed

+28
-4
lines changed

3 files changed

+28
-4
lines changed

Lib/test/test_fcntl.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
cpython_only, get_pagesize, is_apple, requires_subprocess, verbose
1212
)
1313
from test.support.import_helper import import_module
14-
from test.support.os_helper import TESTFN, unlink
14+
from test.support.os_helper import TESTFN, unlink, make_bad_fd
1515

1616

1717
# Skip test if no fcntl module.
@@ -274,6 +274,17 @@ def test_fcntl_small_buffer(self):
274274
def test_fcntl_large_buffer(self):
275275
self._check_fcntl_not_mutate_len(2024)
276276

277+
@unittest.skipUnless(hasattr(fcntl, 'F_DUPFD'), 'need fcntl.F_DUPFD')
278+
def test_bad_fd(self):
279+
# gh-134744: Test error handling
280+
fd = make_bad_fd()
281+
with self.assertRaises(OSError):
282+
fcntl.fcntl(fd, fcntl.F_DUPFD, 0)
283+
with self.assertRaises(OSError):
284+
fcntl.fcntl(fd, fcntl.F_DUPFD, b'\0' * 10)
285+
with self.assertRaises(OSError):
286+
fcntl.fcntl(fd, fcntl.F_DUPFD, b'\0' * 2048)
287+
277288

278289
if __name__ == '__main__':
279290
unittest.main()

Lib/test/test_ioctl.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import threading
66
import unittest
77
from test import support
8-
from test.support import threading_helper
8+
from test.support import os_helper, threading_helper
99
from test.support.import_helper import import_module
1010
fcntl = import_module('fcntl')
1111
termios = import_module('termios')
@@ -201,6 +201,17 @@ def test_ioctl_set_window_size(self):
201201
new_winsz = struct.unpack("HHHH", result)
202202
self.assertEqual(new_winsz[:2], (20, 40))
203203

204+
@unittest.skipUnless(hasattr(fcntl, 'FICLONE'), 'need fcntl.FICLONE')
205+
def test_bad_fd(self):
206+
# gh-134744: Test error handling
207+
fd = os_helper.make_bad_fd()
208+
with self.assertRaises(OSError):
209+
fcntl.ioctl(fd, fcntl.FICLONE, fd)
210+
with self.assertRaises(OSError):
211+
fcntl.ioctl(fd, fcntl.FICLONE, b'\0' * 10)
212+
with self.assertRaises(OSError):
213+
fcntl.ioctl(fd, fcntl.FICLONE, b'\0' * 2048)
214+
204215

205216
if __name__ == "__main__":
206217
unittest.main()

Modules/fcntlmodule.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,15 @@ fcntl_fcntl_impl(PyObject *module, int fd, int code, PyObject *arg)
128128
Py_END_ALLOW_THREADS
129129
} while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
130130
if (ret < 0) {
131-
if (async_err) {
131+
if (!async_err) {
132132
PyErr_SetFromErrno(PyExc_OSError);
133133
}
134134
Py_DECREF(result);
135135
return NULL;
136136
}
137137
if (ptr[len] != '\0') {
138138
PyErr_SetString(PyExc_SystemError, "buffer overflow");
139+
Py_DECREF(result);
139140
return NULL;
140141
}
141142
return result;
@@ -310,14 +311,15 @@ fcntl_ioctl_impl(PyObject *module, int fd, unsigned long code, PyObject *arg,
310311
Py_END_ALLOW_THREADS
311312
} while (ret == -1 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
312313
if (ret < 0) {
313-
if (async_err) {
314+
if (!async_err) {
314315
PyErr_SetFromErrno(PyExc_OSError);
315316
}
316317
Py_DECREF(result);
317318
return NULL;
318319
}
319320
if (ptr[len] != '\0') {
320321
PyErr_SetString(PyExc_SystemError, "buffer overflow");
322+
Py_DECREF(result);
321323
return NULL;
322324
}
323325
return result;

0 commit comments

Comments
 (0)