Skip to content

Commit 400bef9

Browse files
committed
bpo-40638: Check for attribute lookup failure in builtin_input_impl
Add tests to cover this case.
1 parent 62d618c commit 400bef9

File tree

2 files changed

+36
-6
lines changed

2 files changed

+36
-6
lines changed

Lib/test/test_builtin.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,23 @@ class BitBucket:
7575
def write(self, line):
7676
pass
7777

78+
class MalformedInputStream:
79+
def readline(self):
80+
return "foobar\n"
81+
82+
def fileno(self):
83+
return 0
84+
85+
class MalformedOutputStream:
86+
def __init__(self):
87+
self.value = ""
88+
89+
def fileno(self):
90+
return 1
91+
92+
def write(self, value):
93+
self.value += value
94+
7895
test_conv_no_sign = [
7996
('0', 0),
8097
('1', 1),
@@ -1302,6 +1319,13 @@ def test_input(self):
13021319
sys.stdin = io.StringIO()
13031320
self.assertRaises(EOFError, input)
13041321

1322+
# input() in tty mode with a malformed input stream should attempt
1323+
# to call .readline()
1324+
sys.stdin = MalformedInputStream()
1325+
sys.stdout = MalformedOutputStream()
1326+
self.assertEqual(input("baz"), "foobar") # strips \n
1327+
self.assertEqual(sys.stdout.value, "baz")
1328+
13051329
del sys.stdout
13061330
self.assertRaises(RuntimeError, input, 'prompt')
13071331
del sys.stdin

Python/bltinmodule.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,17 +2010,21 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
20102010

20112011
/* stdin is a text stream, so it must have an encoding. */
20122012
stdin_encoding = _PyObject_GetAttrId(fin, &PyId_encoding);
2013+
if (!stdin_encoding || !PyUnicode_Check(stdin_encoding)) {
2014+
goto _readline_disable_tty_and_fall_back;
2015+
}
20132016
stdin_errors = _PyObject_GetAttrId(fin, &PyId_errors);
2014-
if (!stdin_encoding || !stdin_errors ||
2015-
!PyUnicode_Check(stdin_encoding) ||
2016-
!PyUnicode_Check(stdin_errors)) {
2017-
tty = 0;
2018-
goto _readline_errors;
2017+
if (!stdin_errors || !PyUnicode_Check(stdin_errors)) {
2018+
goto _readline_disable_tty_and_fall_back;
20192019
}
20202020
stdin_encoding_str = PyUnicode_AsUTF8(stdin_encoding);
2021+
if (!stdin_encoding_str) {
2022+
goto _readline_errors;
2023+
}
20212024
stdin_errors_str = PyUnicode_AsUTF8(stdin_errors);
2022-
if (!stdin_encoding_str || !stdin_errors_str)
2025+
if (!stdin_errors_str) {
20232026
goto _readline_errors;
2027+
}
20242028
tmp = _PyObject_CallMethodIdNoArgs(fout, &PyId_flush);
20252029
if (tmp == NULL)
20262030
PyErr_Clear();
@@ -2099,6 +2103,8 @@ builtin_input_impl(PyObject *module, PyObject *prompt)
20992103

21002104
return result;
21012105

2106+
_readline_disable_tty_and_fall_back:
2107+
tty = 0;
21022108
_readline_errors:
21032109
Py_XDECREF(stdin_encoding);
21042110
Py_XDECREF(stdout_encoding);

0 commit comments

Comments
 (0)