Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3797065

Browse files
committed
#19395: Raise exception when pickling a (BZ2|LZMA)(Compressor|Decompressor).
The underlying C libraries provide no mechanism for serializing compressor and decompressor objects, so actually pickling these classes is impractical. Previously, these objects would be pickled without error, but attempting to use a deserialized instance would segfault the interpreter.
1 parent ba4e58a commit 3797065

5 files changed

Lines changed: 61 additions & 2 deletions

File tree

Lib/test/test_bz2.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import unittest
66
from io import BytesIO
77
import os
8+
import pickle
89
import random
910
import subprocess
1011
import sys
@@ -621,6 +622,11 @@ def testCompress4G(self, size):
621622
finally:
622623
data = None
623624

625+
def testPickle(self):
626+
with self.assertRaises(TypeError):
627+
pickle.dumps(BZ2Compressor())
628+
629+
624630
class BZ2DecompressorTest(BaseTest):
625631
def test_Constructor(self):
626632
self.assertRaises(TypeError, BZ2Decompressor, 42)
@@ -672,6 +678,10 @@ def testDecompress4G(self, size):
672678
compressed = None
673679
decompressed = None
674680

681+
def testPickle(self):
682+
with self.assertRaises(TypeError):
683+
pickle.dumps(BZ2Decompressor())
684+
675685

676686
class CompressDecompressTest(BaseTest):
677687
def testCompress(self):

Lib/test/test_lzma.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from io import BytesIO, UnsupportedOperation
22
import os
3+
import pickle
34
import random
45
import unittest
56

@@ -216,6 +217,14 @@ def test_decompressor_bigmem(self, size):
216217
finally:
217218
input = cdata = ddata = None
218219

220+
# Pickling raises an exception; there's no way to serialize an lzma_stream.
221+
222+
def test_pickle(self):
223+
with self.assertRaises(TypeError):
224+
pickle.dumps(LZMACompressor())
225+
with self.assertRaises(TypeError):
226+
pickle.dumps(LZMADecompressor())
227+
219228

220229
class CompressDecompressFunctionTestCase(unittest.TestCase):
221230

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ Core and Builtins
9292
Library
9393
-------
9494

95+
- Issue #19395: Raise an exception when attempting to pickle a bz2 or lzma
96+
compressor/decompressor object, rather than creating a pickle that would
97+
cause a segfault when loaded and used.
98+
9599
- Issue #19227: Try to fix deadlocks caused by re-seeding then OpenSSL
96100
pseudo-random number generator on fork().
97101

Modules/_bz2module.c

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,14 @@ BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs)
250250
return result;
251251
}
252252

253+
static PyObject *
254+
BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
255+
{
256+
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
257+
Py_TYPE(self)->tp_name);
258+
return NULL;
259+
}
260+
253261
static int
254262
BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs)
255263
{
@@ -298,10 +306,11 @@ BZ2Compressor_dealloc(BZ2Compressor *self)
298306
}
299307

300308
static PyMethodDef BZ2Compressor_methods[] = {
301-
{"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS,
309+
{"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS,
302310
BZ2Compressor_compress__doc__},
303-
{"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS,
311+
{"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS,
304312
BZ2Compressor_flush__doc__},
313+
{"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
305314
{NULL}
306315
};
307316

@@ -452,6 +461,14 @@ BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args)
452461
return result;
453462
}
454463

464+
static PyObject *
465+
BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
466+
{
467+
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
468+
Py_TYPE(self)->tp_name);
469+
return NULL;
470+
}
471+
455472
static int
456473
BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs)
457474
{
@@ -502,6 +519,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self)
502519
static PyMethodDef BZ2Decompressor_methods[] = {
503520
{"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS,
504521
BZ2Decompressor_decompress__doc__},
522+
{"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
505523
{NULL}
506524
};
507525

Modules/_lzmamodule.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,14 @@ Compressor_flush(Compressor *self, PyObject *noargs)
546546
return result;
547547
}
548548

549+
static PyObject *
550+
Compressor_getstate(Compressor *self, PyObject *noargs)
551+
{
552+
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
553+
Py_TYPE(self)->tp_name);
554+
return NULL;
555+
}
556+
549557
static int
550558
Compressor_init_xz(lzma_stream *lzs, int check, uint32_t preset,
551559
PyObject *filterspecs)
@@ -712,6 +720,7 @@ static PyMethodDef Compressor_methods[] = {
712720
Compressor_compress_doc},
713721
{"flush", (PyCFunction)Compressor_flush, METH_NOARGS,
714722
Compressor_flush_doc},
723+
{"__getstate__", (PyCFunction)Compressor_getstate, METH_NOARGS},
715724
{NULL}
716725
};
717726

@@ -869,6 +878,14 @@ Decompressor_decompress(Decompressor *self, PyObject *args)
869878
return result;
870879
}
871880

881+
static PyObject *
882+
Decompressor_getstate(Decompressor *self, PyObject *noargs)
883+
{
884+
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
885+
Py_TYPE(self)->tp_name);
886+
return NULL;
887+
}
888+
872889
static int
873890
Decompressor_init_raw(lzma_stream *lzs, PyObject *filterspecs)
874891
{
@@ -991,6 +1008,7 @@ Decompressor_dealloc(Decompressor *self)
9911008
static PyMethodDef Decompressor_methods[] = {
9921009
{"decompress", (PyCFunction)Decompressor_decompress, METH_VARARGS,
9931010
Decompressor_decompress_doc},
1011+
{"__getstate__", (PyCFunction)Decompressor_getstate, METH_NOARGS},
9941012
{NULL}
9951013
};
9961014

0 commit comments

Comments
 (0)