Skip to content

Commit 488c0a6

Browse files
libcthornemethane
authored andcommitted
bpo-33578: Fix getstate/setstate for CJK decoder (GH-10290)
Previous version was casting to Py_ssize_t incorrectly and exhibited unexpected behavior on big-endian systems.
1 parent 318ab63 commit 488c0a6

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

Lib/test/test_multibytecodec.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ def test_state_methods(self):
271271
pending4, _ = decoder.getstate()
272272
self.assertEqual(pending4, b'')
273273

274+
# Ensure state values are preserved correctly
275+
decoder.setstate((b'abc', 123456789))
276+
self.assertEqual(decoder.getstate(), (b'abc', 123456789))
277+
274278
def test_setstate_validates_input(self):
275279
decoder = codecs.getincrementaldecoder('euc_jp')()
276280
self.assertRaises(TypeError, decoder.setstate, 123)

Modules/cjkcodecs/multibytecodec.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,14 +1218,24 @@ _multibytecodec_MultibyteIncrementalDecoder_getstate_impl(MultibyteIncrementalDe
12181218
/*[clinic end generated code: output=255009c4713b7f82 input=4006aa49bddbaa75]*/
12191219
{
12201220
PyObject *buffer;
1221+
PyObject *statelong;
12211222

12221223
buffer = PyBytes_FromStringAndSize((const char *)self->pending,
12231224
self->pendingsize);
12241225
if (buffer == NULL) {
12251226
return NULL;
12261227
}
12271228

1228-
return make_tuple(buffer, (Py_ssize_t)*self->state.c);
1229+
statelong = (PyObject *)_PyLong_FromByteArray(self->state.c,
1230+
sizeof(self->state.c),
1231+
1 /* little-endian */ ,
1232+
0 /* unsigned */ );
1233+
if (statelong == NULL) {
1234+
Py_DECREF(buffer);
1235+
return NULL;
1236+
}
1237+
1238+
return Py_BuildValue("NN", buffer, statelong);
12291239
}
12301240

12311241
/*[clinic input]
@@ -1240,16 +1250,23 @@ _multibytecodec_MultibyteIncrementalDecoder_setstate_impl(MultibyteIncrementalDe
12401250
/*[clinic end generated code: output=106b2fbca3e2dcc2 input=e5d794e8baba1a47]*/
12411251
{
12421252
PyObject *buffer;
1253+
PyLongObject *statelong;
12431254
Py_ssize_t buffersize;
12441255
char *bufferstr;
1245-
unsigned long long flag;
1256+
unsigned char statebytes[8];
12461257

1247-
if (!PyArg_ParseTuple(state, "SK;setstate(): illegal state argument",
1248-
&buffer, &flag))
1258+
if (!PyArg_ParseTuple(state, "SO!;setstate(): illegal state argument",
1259+
&buffer, &PyLong_Type, &statelong))
12491260
{
12501261
return NULL;
12511262
}
12521263

1264+
if (_PyLong_AsByteArray(statelong, statebytes, sizeof(statebytes),
1265+
1 /* little-endian */ ,
1266+
0 /* unsigned */ ) < 0) {
1267+
return NULL;
1268+
}
1269+
12531270
buffersize = PyBytes_Size(buffer);
12541271
if (buffersize == -1) {
12551272
return NULL;
@@ -1266,7 +1283,7 @@ _multibytecodec_MultibyteIncrementalDecoder_setstate_impl(MultibyteIncrementalDe
12661283
}
12671284
self->pendingsize = buffersize;
12681285
memcpy(self->pending, bufferstr, self->pendingsize);
1269-
memcpy(self->state.c, (unsigned char *)&flag, sizeof(flag));
1286+
memcpy(self->state.c, statebytes, sizeof(statebytes));
12701287

12711288
Py_RETURN_NONE;
12721289
}

0 commit comments

Comments
 (0)