Commit 3797065a authored by Nadeem Vawda's avatar Nadeem Vawda

#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.
parent ba4e58a0
...@@ -5,6 +5,7 @@ from test.support import TESTFN, bigmemtest, _4G ...@@ -5,6 +5,7 @@ from test.support import TESTFN, bigmemtest, _4G
import unittest import unittest
from io import BytesIO from io import BytesIO
import os import os
import pickle
import random import random
import subprocess import subprocess
import sys import sys
...@@ -621,6 +622,11 @@ class BZ2CompressorTest(BaseTest): ...@@ -621,6 +622,11 @@ class BZ2CompressorTest(BaseTest):
finally: finally:
data = None data = None
def testPickle(self):
with self.assertRaises(TypeError):
pickle.dumps(BZ2Compressor())
class BZ2DecompressorTest(BaseTest): class BZ2DecompressorTest(BaseTest):
def test_Constructor(self): def test_Constructor(self):
self.assertRaises(TypeError, BZ2Decompressor, 42) self.assertRaises(TypeError, BZ2Decompressor, 42)
...@@ -672,6 +678,10 @@ class BZ2DecompressorTest(BaseTest): ...@@ -672,6 +678,10 @@ class BZ2DecompressorTest(BaseTest):
compressed = None compressed = None
decompressed = None decompressed = None
def testPickle(self):
with self.assertRaises(TypeError):
pickle.dumps(BZ2Decompressor())
class CompressDecompressTest(BaseTest): class CompressDecompressTest(BaseTest):
def testCompress(self): def testCompress(self):
......
from io import BytesIO, UnsupportedOperation from io import BytesIO, UnsupportedOperation
import os import os
import pickle
import random import random
import unittest import unittest
...@@ -216,6 +217,14 @@ class CompressorDecompressorTestCase(unittest.TestCase): ...@@ -216,6 +217,14 @@ class CompressorDecompressorTestCase(unittest.TestCase):
finally: finally:
input = cdata = ddata = None input = cdata = ddata = None
# Pickling raises an exception; there's no way to serialize an lzma_stream.
def test_pickle(self):
with self.assertRaises(TypeError):
pickle.dumps(LZMACompressor())
with self.assertRaises(TypeError):
pickle.dumps(LZMADecompressor())
class CompressDecompressFunctionTestCase(unittest.TestCase): class CompressDecompressFunctionTestCase(unittest.TestCase):
......
...@@ -92,6 +92,10 @@ Core and Builtins ...@@ -92,6 +92,10 @@ Core and Builtins
Library Library
------- -------
- Issue #19395: Raise an exception when attempting to pickle a bz2 or lzma
compressor/decompressor object, rather than creating a pickle that would
cause a segfault when loaded and used.
- Issue #19227: Try to fix deadlocks caused by re-seeding then OpenSSL - Issue #19227: Try to fix deadlocks caused by re-seeding then OpenSSL
pseudo-random number generator on fork(). pseudo-random number generator on fork().
......
...@@ -250,6 +250,14 @@ BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs) ...@@ -250,6 +250,14 @@ BZ2Compressor_flush(BZ2Compressor *self, PyObject *noargs)
return result; return result;
} }
static PyObject *
BZ2Compressor_getstate(BZ2Compressor *self, PyObject *noargs)
{
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
Py_TYPE(self)->tp_name);
return NULL;
}
static int static int
BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs) BZ2Compressor_init(BZ2Compressor *self, PyObject *args, PyObject *kwargs)
{ {
...@@ -298,10 +306,11 @@ BZ2Compressor_dealloc(BZ2Compressor *self) ...@@ -298,10 +306,11 @@ BZ2Compressor_dealloc(BZ2Compressor *self)
} }
static PyMethodDef BZ2Compressor_methods[] = { static PyMethodDef BZ2Compressor_methods[] = {
{"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS, {"compress", (PyCFunction)BZ2Compressor_compress, METH_VARARGS,
BZ2Compressor_compress__doc__}, BZ2Compressor_compress__doc__},
{"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS, {"flush", (PyCFunction)BZ2Compressor_flush, METH_NOARGS,
BZ2Compressor_flush__doc__}, BZ2Compressor_flush__doc__},
{"__getstate__", (PyCFunction)BZ2Compressor_getstate, METH_NOARGS},
{NULL} {NULL}
}; };
...@@ -452,6 +461,14 @@ BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args) ...@@ -452,6 +461,14 @@ BZ2Decompressor_decompress(BZ2Decompressor *self, PyObject *args)
return result; return result;
} }
static PyObject *
BZ2Decompressor_getstate(BZ2Decompressor *self, PyObject *noargs)
{
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
Py_TYPE(self)->tp_name);
return NULL;
}
static int static int
BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs) BZ2Decompressor_init(BZ2Decompressor *self, PyObject *args, PyObject *kwargs)
{ {
...@@ -502,6 +519,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self) ...@@ -502,6 +519,7 @@ BZ2Decompressor_dealloc(BZ2Decompressor *self)
static PyMethodDef BZ2Decompressor_methods[] = { static PyMethodDef BZ2Decompressor_methods[] = {
{"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS, {"decompress", (PyCFunction)BZ2Decompressor_decompress, METH_VARARGS,
BZ2Decompressor_decompress__doc__}, BZ2Decompressor_decompress__doc__},
{"__getstate__", (PyCFunction)BZ2Decompressor_getstate, METH_NOARGS},
{NULL} {NULL}
}; };
......
...@@ -546,6 +546,14 @@ Compressor_flush(Compressor *self, PyObject *noargs) ...@@ -546,6 +546,14 @@ Compressor_flush(Compressor *self, PyObject *noargs)
return result; return result;
} }
static PyObject *
Compressor_getstate(Compressor *self, PyObject *noargs)
{
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
Py_TYPE(self)->tp_name);
return NULL;
}
static int static int
Compressor_init_xz(lzma_stream *lzs, int check, uint32_t preset, Compressor_init_xz(lzma_stream *lzs, int check, uint32_t preset,
PyObject *filterspecs) PyObject *filterspecs)
...@@ -712,6 +720,7 @@ static PyMethodDef Compressor_methods[] = { ...@@ -712,6 +720,7 @@ static PyMethodDef Compressor_methods[] = {
Compressor_compress_doc}, Compressor_compress_doc},
{"flush", (PyCFunction)Compressor_flush, METH_NOARGS, {"flush", (PyCFunction)Compressor_flush, METH_NOARGS,
Compressor_flush_doc}, Compressor_flush_doc},
{"__getstate__", (PyCFunction)Compressor_getstate, METH_NOARGS},
{NULL} {NULL}
}; };
...@@ -869,6 +878,14 @@ Decompressor_decompress(Decompressor *self, PyObject *args) ...@@ -869,6 +878,14 @@ Decompressor_decompress(Decompressor *self, PyObject *args)
return result; return result;
} }
static PyObject *
Decompressor_getstate(Decompressor *self, PyObject *noargs)
{
PyErr_Format(PyExc_TypeError, "cannot serialize '%s' object",
Py_TYPE(self)->tp_name);
return NULL;
}
static int static int
Decompressor_init_raw(lzma_stream *lzs, PyObject *filterspecs) Decompressor_init_raw(lzma_stream *lzs, PyObject *filterspecs)
{ {
...@@ -991,6 +1008,7 @@ Decompressor_dealloc(Decompressor *self) ...@@ -991,6 +1008,7 @@ Decompressor_dealloc(Decompressor *self)
static PyMethodDef Decompressor_methods[] = { static PyMethodDef Decompressor_methods[] = {
{"decompress", (PyCFunction)Decompressor_decompress, METH_VARARGS, {"decompress", (PyCFunction)Decompressor_decompress, METH_VARARGS,
Decompressor_decompress_doc}, Decompressor_decompress_doc},
{"__getstate__", (PyCFunction)Decompressor_getstate, METH_NOARGS},
{NULL} {NULL}
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment