#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:
Amaury Forgeot d'Arc 2008-10-17 20:15:53 +00:00
parent 869bad9b5a
commit 87eee631fb
3 changed files with 33 additions and 1 deletions

View File

@ -996,6 +996,20 @@ class AbstractPickleModuleTests(unittest.TestCase):
pickle.Pickler(f, -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):
# This class defines persistent_id() and persistent_load()

View File

@ -33,7 +33,10 @@ Core and Builtins
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.

View File

@ -421,6 +421,11 @@ pickler_write(PicklerObject *self, const char *s, Py_ssize_t n)
{
PyObject *data, *result;
if (self->write_buf == NULL) {
PyErr_SetString(PyExc_SystemError, "invalid write buffer");
return -1;
}
if (s == NULL) {
if (!(self->buf_size))
return 0;
@ -2378,6 +2383,16 @@ Pickler_dump(PicklerObject *self, PyObject *args)
{
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))
return NULL;