Skip to content

Commit a851797

Browse files
[3.10] bpo-31718: Fix io.IncrementalNewlineDecoder SystemErrors and s… (#99842)
[3.10] bpo-31718: Fix io.IncrementalNewlineDecoder SystemErrors and segfaults (GH-18640) Co-authored-by: Oren Milman <[email protected]> Co-authored-by: Kumar Aditya <[email protected]>. (cherry picked from commit 53eef27) Co-authored-by: Zackery Spytz <[email protected]>
1 parent b1c148c commit a851797

File tree

3 files changed

+33
-14
lines changed

3 files changed

+33
-14
lines changed

Lib/test/test_io.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3926,7 +3926,15 @@ def test_translate(self):
39263926
self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n")
39273927

39283928
class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
3929-
pass
3929+
@support.cpython_only
3930+
def test_uninitialized(self):
3931+
uninitialized = self.IncrementalNewlineDecoder.__new__(
3932+
self.IncrementalNewlineDecoder)
3933+
self.assertRaises(ValueError, uninitialized.decode, b'bar')
3934+
self.assertRaises(ValueError, uninitialized.getstate)
3935+
self.assertRaises(ValueError, uninitialized.setstate, (b'foo', 0))
3936+
self.assertRaises(ValueError, uninitialized.reset)
3937+
39303938

39313939
class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
39323940
pass
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Raise :exc:`ValueError` instead of :exc:`SystemError` when methods of
2+
uninitialized :class:`io.IncrementalNewlineDecoder` objects are called.
3+
Patch by Oren Milman.

Modules/_io/textio.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -251,19 +251,16 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
251251
PyObject *errors)
252252
/*[clinic end generated code: output=fbd04d443e764ec2 input=89db6b19c6b126bf]*/
253253
{
254-
self->decoder = decoder;
255-
Py_INCREF(decoder);
256254

257255
if (errors == NULL) {
258-
self->errors = _PyUnicode_FromId(&PyId_strict);
259-
if (self->errors == NULL)
256+
errors = _PyUnicode_FromId(&PyId_strict);
257+
if (errors == NULL) {
260258
return -1;
259+
}
261260
}
262-
else {
263-
self->errors = errors;
264-
}
265-
Py_INCREF(self->errors);
266261

262+
Py_XSETREF(self->errors, Py_NewRef(errors));
263+
Py_XSETREF(self->decoder, Py_NewRef(decoder));
267264
self->translate = translate ? 1 : 0;
268265
self->seennl = 0;
269266
self->pendingcr = 0;
@@ -298,6 +295,13 @@ check_decoded(PyObject *decoded)
298295
return 0;
299296
}
300297

298+
#define CHECK_INITIALIZED_DECODER(self) \
299+
if (self->errors == NULL) { \
300+
PyErr_SetString(PyExc_ValueError, \
301+
"IncrementalNewlineDecoder.__init__() not called"); \
302+
return NULL; \
303+
}
304+
301305
#define SEEN_CR 1
302306
#define SEEN_LF 2
303307
#define SEEN_CRLF 4
@@ -311,11 +315,7 @@ _PyIncrementalNewlineDecoder_decode(PyObject *myself,
311315
Py_ssize_t output_len;
312316
nldecoder_object *self = (nldecoder_object *) myself;
313317

314-
if (self->decoder == NULL) {
315-
PyErr_SetString(PyExc_ValueError,
316-
"IncrementalNewlineDecoder.__init__ not called");
317-
return NULL;
318-
}
318+
CHECK_INITIALIZED_DECODER(self);
319319

320320
/* decode input (with the eventual \r from a previous pass) */
321321
if (self->decoder != Py_None) {
@@ -529,6 +529,8 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self)
529529
PyObject *buffer;
530530
unsigned long long flag;
531531

532+
CHECK_INITIALIZED_DECODER(self);
533+
532534
if (self->decoder != Py_None) {
533535
PyObject *state = PyObject_CallMethodNoArgs(self->decoder,
534536
_PyIO_str_getstate);
@@ -573,6 +575,8 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self,
573575
PyObject *buffer;
574576
unsigned long long flag;
575577

578+
CHECK_INITIALIZED_DECODER(self);
579+
576580
if (!PyTuple_Check(state)) {
577581
PyErr_SetString(PyExc_TypeError, "state argument must be a tuple");
578582
return NULL;
@@ -601,6 +605,8 @@ static PyObject *
601605
_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
602606
/*[clinic end generated code: output=32fa40c7462aa8ff input=728678ddaea776df]*/
603607
{
608+
CHECK_INITIALIZED_DECODER(self);
609+
604610
self->seennl = 0;
605611
self->pendingcr = 0;
606612
if (self->decoder != Py_None)
@@ -612,6 +618,8 @@ _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
612618
static PyObject *
613619
incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context)
614620
{
621+
CHECK_INITIALIZED_DECODER(self);
622+
615623
switch (self->seennl) {
616624
case SEEN_CR:
617625
return PyUnicode_FromString("\r");

0 commit comments

Comments
 (0)