Skip to content

Commit

Permalink
[3.10] bpo-31718: Fix io.IncrementalNewlineDecoder SystemErrors and s… (
Browse files Browse the repository at this point in the history
#99842)

[3.10] bpo-31718: Fix io.IncrementalNewlineDecoder SystemErrors and segfaults (GH-18640)

Co-authored-by: Oren Milman <orenmn@gmail.com>
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>.
(cherry picked from commit 53eef27)

Co-authored-by: Zackery Spytz <zspytz@gmail.com>
  • Loading branch information
kumaraditya303 and ZackerySpytz authored Nov 28, 2022
1 parent b1c148c commit a851797
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
10 changes: 9 additions & 1 deletion Lib/test/test_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -3926,7 +3926,15 @@ def test_translate(self):
self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n")

class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
pass
@support.cpython_only
def test_uninitialized(self):
uninitialized = self.IncrementalNewlineDecoder.__new__(
self.IncrementalNewlineDecoder)
self.assertRaises(ValueError, uninitialized.decode, b'bar')
self.assertRaises(ValueError, uninitialized.getstate)
self.assertRaises(ValueError, uninitialized.setstate, (b'foo', 0))
self.assertRaises(ValueError, uninitialized.reset)


class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
pass
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Raise :exc:`ValueError` instead of :exc:`SystemError` when methods of
uninitialized :class:`io.IncrementalNewlineDecoder` objects are called.
Patch by Oren Milman.
34 changes: 21 additions & 13 deletions Modules/_io/textio.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,19 +251,16 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
PyObject *errors)
/*[clinic end generated code: output=fbd04d443e764ec2 input=89db6b19c6b126bf]*/
{
self->decoder = decoder;
Py_INCREF(decoder);

if (errors == NULL) {
self->errors = _PyUnicode_FromId(&PyId_strict);
if (self->errors == NULL)
errors = _PyUnicode_FromId(&PyId_strict);
if (errors == NULL) {
return -1;
}
}
else {
self->errors = errors;
}
Py_INCREF(self->errors);

Py_XSETREF(self->errors, Py_NewRef(errors));
Py_XSETREF(self->decoder, Py_NewRef(decoder));
self->translate = translate ? 1 : 0;
self->seennl = 0;
self->pendingcr = 0;
Expand Down Expand Up @@ -298,6 +295,13 @@ check_decoded(PyObject *decoded)
return 0;
}

#define CHECK_INITIALIZED_DECODER(self) \
if (self->errors == NULL) { \
PyErr_SetString(PyExc_ValueError, \
"IncrementalNewlineDecoder.__init__() not called"); \
return NULL; \
}

#define SEEN_CR 1
#define SEEN_LF 2
#define SEEN_CRLF 4
Expand All @@ -311,11 +315,7 @@ _PyIncrementalNewlineDecoder_decode(PyObject *myself,
Py_ssize_t output_len;
nldecoder_object *self = (nldecoder_object *) myself;

if (self->decoder == NULL) {
PyErr_SetString(PyExc_ValueError,
"IncrementalNewlineDecoder.__init__ not called");
return NULL;
}
CHECK_INITIALIZED_DECODER(self);

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

CHECK_INITIALIZED_DECODER(self);

if (self->decoder != Py_None) {
PyObject *state = PyObject_CallMethodNoArgs(self->decoder,
_PyIO_str_getstate);
Expand Down Expand Up @@ -573,6 +575,8 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self,
PyObject *buffer;
unsigned long long flag;

CHECK_INITIALIZED_DECODER(self);

if (!PyTuple_Check(state)) {
PyErr_SetString(PyExc_TypeError, "state argument must be a tuple");
return NULL;
Expand Down Expand Up @@ -601,6 +605,8 @@ static PyObject *
_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
/*[clinic end generated code: output=32fa40c7462aa8ff input=728678ddaea776df]*/
{
CHECK_INITIALIZED_DECODER(self);

self->seennl = 0;
self->pendingcr = 0;
if (self->decoder != Py_None)
Expand All @@ -612,6 +618,8 @@ _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
static PyObject *
incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context)
{
CHECK_INITIALIZED_DECODER(self);

switch (self->seennl) {
case SEEN_CR:
return PyUnicode_FromString("\r");
Expand Down

0 comments on commit a851797

Please sign in to comment.