#3664: The pickle module could segfault if a Pickler instance is not correctly initialized:
when a subclass forgets to call the base __init__ method, or when __init__ is called a second time with invalid parameters Patch by Alexandre Vassalotti.
This commit is contained in:
parent
869bad9b5a
commit
87eee631fb
|
@ -996,6 +996,20 @@ class AbstractPickleModuleTests(unittest.TestCase):
|
||||||
pickle.Pickler(f, -1)
|
pickle.Pickler(f, -1)
|
||||||
pickle.Pickler(f, protocol=-1)
|
pickle.Pickler(f, protocol=-1)
|
||||||
|
|
||||||
|
def test_bad_init(self):
|
||||||
|
# Test issue3664 (pickle can segfault from a badly initialized Pickler).
|
||||||
|
from io import BytesIO
|
||||||
|
# Override initialization without calling __init__() of the superclass.
|
||||||
|
class BadPickler(pickle.Pickler):
|
||||||
|
def __init__(self): pass
|
||||||
|
|
||||||
|
class BadUnpickler(pickle.Unpickler):
|
||||||
|
def __init__(self): pass
|
||||||
|
|
||||||
|
self.assertRaises(pickle.PicklingError, BadPickler().dump, 0)
|
||||||
|
self.assertRaises(pickle.UnpicklingError, BadUnpickler().load)
|
||||||
|
|
||||||
|
|
||||||
class AbstractPersistentPicklerTests(unittest.TestCase):
|
class AbstractPersistentPicklerTests(unittest.TestCase):
|
||||||
|
|
||||||
# This class defines persistent_id() and persistent_load()
|
# This class defines persistent_id() and persistent_load()
|
||||||
|
|
|
@ -33,7 +33,10 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
- telnetlib now works completely in bytes.
|
- Issue #3664: The pickle module could segfault if a subclass of Pickler fails
|
||||||
|
to call the base __init__ method.
|
||||||
|
|
||||||
|
- Issue #3725: telnetlib now works completely in bytes.
|
||||||
|
|
||||||
- Issue #4072: Restore build_py_2to3.
|
- Issue #4072: Restore build_py_2to3.
|
||||||
|
|
||||||
|
|
|
@ -421,6 +421,11 @@ pickler_write(PicklerObject *self, const char *s, Py_ssize_t n)
|
||||||
{
|
{
|
||||||
PyObject *data, *result;
|
PyObject *data, *result;
|
||||||
|
|
||||||
|
if (self->write_buf == NULL) {
|
||||||
|
PyErr_SetString(PyExc_SystemError, "invalid write buffer");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (s == NULL) {
|
if (s == NULL) {
|
||||||
if (!(self->buf_size))
|
if (!(self->buf_size))
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2378,6 +2383,16 @@ Pickler_dump(PicklerObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *obj;
|
PyObject *obj;
|
||||||
|
|
||||||
|
/* Check whether the Pickler was initialized correctly (issue3664).
|
||||||
|
Developers often forget to call __init__() in their subclasses, which
|
||||||
|
would trigger a segfault without this check. */
|
||||||
|
if (self->write == NULL) {
|
||||||
|
PyErr_Format(PicklingError,
|
||||||
|
"Pickler.__init__() was not called by %s.__init__()",
|
||||||
|
Py_TYPE(self)->tp_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "O:dump", &obj))
|
if (!PyArg_ParseTuple(args, "O:dump", &obj))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue