Skip to content

Commit 53eef27

Browse files
ZackerySpytzorenmnkumaraditya303
authored
bpo-31718: Fix io.IncrementalNewlineDecoder SystemErrors and segfaults (#18640)
Co-authored-by: Oren Milman <orenmn@gmail.com> Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
1 parent 492dc02 commit 53eef27

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

Lib/test/test_io.py

+9-1
Original file line numberDiff line numberDiff line change
@@ -3945,7 +3945,15 @@ def test_translate(self):
39453945
self.assertEqual(decoder.decode(b"\r\r\n"), "\r\r\n")
39463946

39473947
class CIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
3948-
pass
3948+
@support.cpython_only
3949+
def test_uninitialized(self):
3950+
uninitialized = self.IncrementalNewlineDecoder.__new__(
3951+
self.IncrementalNewlineDecoder)
3952+
self.assertRaises(ValueError, uninitialized.decode, b'bar')
3953+
self.assertRaises(ValueError, uninitialized.getstate)
3954+
self.assertRaises(ValueError, uninitialized.setstate, (b'foo', 0))
3955+
self.assertRaises(ValueError, uninitialized.reset)
3956+
39493957

39503958
class PyIncrementalNewlineDecoderTest(IncrementalNewlineDecoderTest):
39513959
pass
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

+20-8
Original file line numberDiff line numberDiff line change
@@ -231,15 +231,16 @@ _io_IncrementalNewlineDecoder___init___impl(nldecoder_object *self,
231231
PyObject *errors)
232232
/*[clinic end generated code: output=fbd04d443e764ec2 input=89db6b19c6b126bf]*/
233233
{
234-
self->decoder = Py_NewRef(decoder);
235234

236235
if (errors == NULL) {
237-
self->errors = Py_NewRef(&_Py_ID(strict));
236+
errors = Py_NewRef(&_Py_ID(strict));
238237
}
239238
else {
240-
self->errors = Py_NewRef(errors);
239+
errors = Py_NewRef(errors);
241240
}
242241

242+
Py_XSETREF(self->errors, errors);
243+
Py_XSETREF(self->decoder, Py_NewRef(decoder));
243244
self->translate = translate ? 1 : 0;
244245
self->seennl = 0;
245246
self->pendingcr = 0;
@@ -274,6 +275,13 @@ check_decoded(PyObject *decoded)
274275
return 0;
275276
}
276277

278+
#define CHECK_INITIALIZED_DECODER(self) \
279+
if (self->errors == NULL) { \
280+
PyErr_SetString(PyExc_ValueError, \
281+
"IncrementalNewlineDecoder.__init__() not called"); \
282+
return NULL; \
283+
}
284+
277285
#define SEEN_CR 1
278286
#define SEEN_LF 2
279287
#define SEEN_CRLF 4
@@ -287,11 +295,7 @@ _PyIncrementalNewlineDecoder_decode(PyObject *myself,
287295
Py_ssize_t output_len;
288296
nldecoder_object *self = (nldecoder_object *) myself;
289297

290-
if (self->decoder == NULL) {
291-
PyErr_SetString(PyExc_ValueError,
292-
"IncrementalNewlineDecoder.__init__ not called");
293-
return NULL;
294-
}
298+
CHECK_INITIALIZED_DECODER(self);
295299

296300
/* decode input (with the eventual \r from a previous pass) */
297301
if (self->decoder != Py_None) {
@@ -502,6 +506,8 @@ _io_IncrementalNewlineDecoder_getstate_impl(nldecoder_object *self)
502506
PyObject *buffer;
503507
unsigned long long flag;
504508

509+
CHECK_INITIALIZED_DECODER(self);
510+
505511
if (self->decoder != Py_None) {
506512
PyObject *state = PyObject_CallMethodNoArgs(self->decoder,
507513
&_Py_ID(getstate));
@@ -546,6 +552,8 @@ _io_IncrementalNewlineDecoder_setstate(nldecoder_object *self,
546552
PyObject *buffer;
547553
unsigned long long flag;
548554

555+
CHECK_INITIALIZED_DECODER(self);
556+
549557
if (!PyTuple_Check(state)) {
550558
PyErr_SetString(PyExc_TypeError, "state argument must be a tuple");
551559
return NULL;
@@ -576,6 +584,8 @@ static PyObject *
576584
_io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
577585
/*[clinic end generated code: output=32fa40c7462aa8ff input=728678ddaea776df]*/
578586
{
587+
CHECK_INITIALIZED_DECODER(self);
588+
579589
self->seennl = 0;
580590
self->pendingcr = 0;
581591
if (self->decoder != Py_None)
@@ -587,6 +597,8 @@ _io_IncrementalNewlineDecoder_reset_impl(nldecoder_object *self)
587597
static PyObject *
588598
incrementalnewlinedecoder_newlines_get(nldecoder_object *self, void *context)
589599
{
600+
CHECK_INITIALIZED_DECODER(self);
601+
590602
switch (self->seennl) {
591603
case SEEN_CR:
592604
return PyUnicode_FromString("\r");

0 commit comments

Comments
 (0)