Skip to content

Commit c7750c2

Browse files
orenmnserhiy-storchaka
authored andcommitted
[3.6] bpo-31243: Fixed PyArg_ParseTuple failure checks. (GH-3171) (#3233)
(cherry picked from commit ba7d736)
1 parent 83e5c88 commit c7750c2

File tree

4 files changed

+65
-21
lines changed

4 files changed

+65
-21
lines changed

Lib/test/test_io.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3191,6 +3191,26 @@ def _make_illegal_wrapper():
31913191
t = _make_illegal_wrapper()
31923192
self.assertRaises(TypeError, t.read)
31933193

3194+
# Issue 31243: calling read() while the return value of decoder's
3195+
# getstate() is invalid should neither crash the interpreter nor
3196+
# raise a SystemError.
3197+
def _make_very_illegal_wrapper(getstate_ret_val):
3198+
class BadDecoder:
3199+
def getstate(self):
3200+
return getstate_ret_val
3201+
def _get_bad_decoder(dummy):
3202+
return BadDecoder()
3203+
quopri = codecs.lookup("quopri")
3204+
with support.swap_attr(quopri, 'incrementaldecoder',
3205+
_get_bad_decoder):
3206+
return _make_illegal_wrapper()
3207+
t = _make_very_illegal_wrapper(42)
3208+
self.assertRaises(TypeError, t.read, 42)
3209+
t = _make_very_illegal_wrapper(())
3210+
self.assertRaises(TypeError, t.read, 42)
3211+
t = _make_very_illegal_wrapper((1, 2))
3212+
self.assertRaises(TypeError, t.read, 42)
3213+
31943214
def _check_create_at_shutdown(self, **kwargs):
31953215
# Issue #20037: creating a TextIOWrapper at shutdown
31963216
# shouldn't crash the interpreter.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a crash in some methods of `io.TextIOWrapper`, when the decoder's state
2+
is invalid. Patch by Oren Milman.

Modules/_io/textio.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,15 +1457,23 @@ textiowrapper_read_chunk(textio *self, Py_ssize_t size_hint)
14571457
/* Given this, we know there was a valid snapshot point
14581458
* len(dec_buffer) bytes ago with decoder state (b'', dec_flags).
14591459
*/
1460-
if (PyArg_ParseTuple(state, "OO", &dec_buffer, &dec_flags) < 0) {
1460+
if (!PyTuple_Check(state)) {
1461+
PyErr_SetString(PyExc_TypeError,
1462+
"illegal decoder state");
1463+
Py_DECREF(state);
1464+
return -1;
1465+
}
1466+
if (!PyArg_ParseTuple(state,
1467+
"OO;illegal decoder state", &dec_buffer, &dec_flags))
1468+
{
14611469
Py_DECREF(state);
14621470
return -1;
14631471
}
14641472

14651473
if (!PyBytes_Check(dec_buffer)) {
14661474
PyErr_Format(PyExc_TypeError,
1467-
"decoder getstate() should have returned a bytes "
1468-
"object, not '%.200s'",
1475+
"illegal decoder state: the first item should be a "
1476+
"bytes object, not '%.200s'",
14691477
Py_TYPE(dec_buffer)->tp_name);
14701478
Py_DECREF(state);
14711479
return -1;
@@ -2349,8 +2357,8 @@ _io_TextIOWrapper_tell_impl(textio *self)
23492357
} \
23502358
if (!PyBytes_Check(dec_buffer)) { \
23512359
PyErr_Format(PyExc_TypeError, \
2352-
"decoder getstate() should have returned a bytes " \
2353-
"object, not '%.200s'", \
2360+
"illegal decoder state: the first item should be a " \
2361+
"bytes object, not '%.200s'", \
23542362
Py_TYPE(dec_buffer)->tp_name); \
23552363
Py_DECREF(_state); \
23562364
goto fail; \

Modules/_testcapimodule.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -870,8 +870,9 @@ test_L_code(PyObject *self)
870870
PyTuple_SET_ITEM(tuple, 0, num);
871871

872872
value = -1;
873-
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0)
873+
if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) {
874874
return NULL;
875+
}
875876
if (value != 42)
876877
return raiseTestError("test_L_code",
877878
"L code returned wrong value for long 42");
@@ -884,8 +885,9 @@ test_L_code(PyObject *self)
884885
PyTuple_SET_ITEM(tuple, 0, num);
885886

886887
value = -1;
887-
if (PyArg_ParseTuple(tuple, "L:test_L_code", &value) < 0)
888+
if (!PyArg_ParseTuple(tuple, "L:test_L_code", &value)) {
888889
return NULL;
890+
}
889891
if (value != 42)
890892
return raiseTestError("test_L_code",
891893
"L code returned wrong value for int 42");
@@ -1202,8 +1204,9 @@ test_k_code(PyObject *self)
12021204
PyTuple_SET_ITEM(tuple, 0, num);
12031205

12041206
value = 0;
1205-
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0)
1207+
if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) {
12061208
return NULL;
1209+
}
12071210
if (value != ULONG_MAX)
12081211
return raiseTestError("test_k_code",
12091212
"k code returned wrong value for long 0xFFF...FFF");
@@ -1221,8 +1224,9 @@ test_k_code(PyObject *self)
12211224
PyTuple_SET_ITEM(tuple, 0, num);
12221225

12231226
value = 0;
1224-
if (PyArg_ParseTuple(tuple, "k:test_k_code", &value) < 0)
1227+
if (!PyArg_ParseTuple(tuple, "k:test_k_code", &value)) {
12251228
return NULL;
1229+
}
12261230
if (value != (unsigned long)-0x42)
12271231
return raiseTestError("test_k_code",
12281232
"k code returned wrong value for long -0xFFF..000042");
@@ -1560,11 +1564,13 @@ test_s_code(PyObject *self)
15601564
/* These two blocks used to raise a TypeError:
15611565
* "argument must be string without null bytes, not str"
15621566
*/
1563-
if (PyArg_ParseTuple(tuple, "s:test_s_code1", &value) < 0)
1564-
return NULL;
1567+
if (!PyArg_ParseTuple(tuple, "s:test_s_code1", &value)) {
1568+
return NULL;
1569+
}
15651570

1566-
if (PyArg_ParseTuple(tuple, "z:test_s_code2", &value) < 0)
1567-
return NULL;
1571+
if (!PyArg_ParseTuple(tuple, "z:test_s_code2", &value)) {
1572+
return NULL;
1573+
}
15681574

15691575
Py_DECREF(tuple);
15701576
Py_RETURN_NONE;
@@ -1666,14 +1672,16 @@ test_u_code(PyObject *self)
16661672
PyTuple_SET_ITEM(tuple, 0, obj);
16671673

16681674
value = 0;
1669-
if (PyArg_ParseTuple(tuple, "u:test_u_code", &value) < 0)
1675+
if (!PyArg_ParseTuple(tuple, "u:test_u_code", &value)) {
16701676
return NULL;
1677+
}
16711678
if (value != PyUnicode_AS_UNICODE(obj))
16721679
return raiseTestError("test_u_code",
16731680
"u code returned wrong value for u'test'");
16741681
value = 0;
1675-
if (PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len) < 0)
1682+
if (!PyArg_ParseTuple(tuple, "u#:test_u_code", &value, &len)) {
16761683
return NULL;
1684+
}
16771685
if (value != PyUnicode_AS_UNICODE(obj) ||
16781686
len != PyUnicode_GET_SIZE(obj))
16791687
return raiseTestError("test_u_code",
@@ -1706,8 +1714,9 @@ test_Z_code(PyObject *self)
17061714
value2 = PyUnicode_AS_UNICODE(obj);
17071715

17081716
/* Test Z for both values */
1709-
if (PyArg_ParseTuple(tuple, "ZZ:test_Z_code", &value1, &value2) < 0)
1717+
if (!PyArg_ParseTuple(tuple, "ZZ:test_Z_code", &value1, &value2)) {
17101718
return NULL;
1719+
}
17111720
if (value1 != PyUnicode_AS_UNICODE(obj))
17121721
return raiseTestError("test_Z_code",
17131722
"Z code returned wrong value for 'test'");
@@ -1721,9 +1730,11 @@ test_Z_code(PyObject *self)
17211730
len2 = -1;
17221731

17231732
/* Test Z# for both values */
1724-
if (PyArg_ParseTuple(tuple, "Z#Z#:test_Z_code", &value1, &len1,
1725-
&value2, &len2) < 0)
1733+
if (!PyArg_ParseTuple(tuple, "Z#Z#:test_Z_code", &value1, &len1,
1734+
&value2, &len2))
1735+
{
17261736
return NULL;
1737+
}
17271738
if (value1 != PyUnicode_AS_UNICODE(obj) ||
17281739
len1 != PyUnicode_GET_SIZE(obj))
17291740
return raiseTestError("test_Z_code",
@@ -2028,17 +2039,19 @@ test_empty_argparse(PyObject *self)
20282039
tuple = PyTuple_New(0);
20292040
if (!tuple)
20302041
return NULL;
2031-
if ((result = PyArg_ParseTuple(tuple, "|:test_empty_argparse")) < 0)
2042+
if (!(result = PyArg_ParseTuple(tuple, "|:test_empty_argparse"))) {
20322043
goto done;
2044+
}
20332045
dict = PyDict_New();
20342046
if (!dict)
20352047
goto done;
20362048
result = PyArg_ParseTupleAndKeywords(tuple, dict, "|:test_empty_argparse", kwlist);
20372049
done:
20382050
Py_DECREF(tuple);
20392051
Py_XDECREF(dict);
2040-
if (result < 0)
2052+
if (!result) {
20412053
return NULL;
2054+
}
20422055
else {
20432056
Py_RETURN_NONE;
20442057
}
@@ -3573,8 +3586,9 @@ test_raise_signal(PyObject* self, PyObject *args)
35733586
{
35743587
int signum, err;
35753588

3576-
if (PyArg_ParseTuple(args, "i:raise_signal", &signum) < 0)
3589+
if (!PyArg_ParseTuple(args, "i:raise_signal", &signum)) {
35773590
return NULL;
3591+
}
35783592

35793593
err = raise(signum);
35803594
if (err)

0 commit comments

Comments
 (0)