Commit 604c013e authored by Tim Peters's avatar Tim Peters

SF 952807: Unpickling pickled instances of subclasses of datetime.date,

datetime.datetime and datetime.time could yield insane objects.  Thanks
to Jiwon Seo for the fix.

Bugfix candidate.  I'll backport it to 2.3.
parent d348193f
...@@ -510,6 +510,9 @@ class TestDateOnly(unittest.TestCase): ...@@ -510,6 +510,9 @@ class TestDateOnly(unittest.TestCase):
dt2 = dt - delta dt2 = dt - delta
self.assertEqual(dt2, dt - days) self.assertEqual(dt2, dt - days)
class SubclassDate(date):
sub_var = 1
class TestDate(HarmlessMixedComparison): class TestDate(HarmlessMixedComparison):
# Tests here should pass for both dates and datetimes, except for a # Tests here should pass for both dates and datetimes, except for a
# few tests that TestDateTime overrides. # few tests that TestDateTime overrides.
...@@ -1029,6 +1032,15 @@ class TestDate(HarmlessMixedComparison): ...@@ -1029,6 +1032,15 @@ class TestDate(HarmlessMixedComparison):
self.assertEqual(dt1.toordinal(), dt2.toordinal()) self.assertEqual(dt1.toordinal(), dt2.toordinal())
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7) self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
def test_pickling_subclass_date(self):
args = 6, 7, 23
orig = SubclassDate(*args)
for pickler, unpickler, proto in pickle_choices:
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
def test_backdoor_resistance(self): def test_backdoor_resistance(self):
# For fast unpickling, the constructor accepts a pickle string. # For fast unpickling, the constructor accepts a pickle string.
# This is a low-overhead backdoor. A user can (by intent or # This is a low-overhead backdoor. A user can (by intent or
...@@ -1053,6 +1065,9 @@ class TestDate(HarmlessMixedComparison): ...@@ -1053,6 +1065,9 @@ class TestDate(HarmlessMixedComparison):
############################################################################# #############################################################################
# datetime tests # datetime tests
class SubclassDatetime(datetime):
sub_var = 1
class TestDateTime(TestDate): class TestDateTime(TestDate):
theclass = datetime theclass = datetime
...@@ -1296,6 +1311,14 @@ class TestDateTime(TestDate): ...@@ -1296,6 +1311,14 @@ class TestDateTime(TestDate):
self.assertEqual(b.month, 2) self.assertEqual(b.month, 2)
self.assertEqual(b.day, 7) self.assertEqual(b.day, 7)
def test_pickling_subclass_datetime(self):
args = 6, 7, 23, 20, 59, 1, 64**2
orig = SubclassDatetime(*args)
for pickler, unpickler, proto in pickle_choices:
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
def test_more_compare(self): def test_more_compare(self):
# The test_compare() inherited from TestDate covers the error cases. # The test_compare() inherited from TestDate covers the error cases.
# We just want to test lexicographic ordering on the members datetime # We just want to test lexicographic ordering on the members datetime
...@@ -1500,6 +1523,9 @@ class TestDateTime(TestDate): ...@@ -1500,6 +1523,9 @@ class TestDateTime(TestDate):
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month + self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
dt1.second - 7) dt1.second - 7)
class SubclassTime(time):
sub_var = 1
class TestTime(HarmlessMixedComparison): class TestTime(HarmlessMixedComparison):
theclass = time theclass = time
...@@ -1700,6 +1726,14 @@ class TestTime(HarmlessMixedComparison): ...@@ -1700,6 +1726,14 @@ class TestTime(HarmlessMixedComparison):
derived = unpickler.loads(green) derived = unpickler.loads(green)
self.assertEqual(orig, derived) self.assertEqual(orig, derived)
def test_pickling_subclass_time(self):
args = 20, 59, 16, 64**2
orig = SubclassTime(*args)
for pickler, unpickler, proto in pickle_choices:
green = pickler.dumps(orig, proto)
derived = unpickler.loads(green)
self.assertEqual(orig, derived)
def test_bool(self): def test_bool(self):
cls = self.theclass cls = self.theclass
self.failUnless(cls(1)) self.failUnless(cls(1))
......
...@@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1? ...@@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1?
Core and builtins Core and builtins
----------------- -----------------
- Bug #952807: Unpickling pickled instances of subclasses of
datetime.date, datetime.datetime and datetime.time could yield insane
objects. Thanks to Jiwon Seo for a fix.
- Bug #845802: Python crashes when __init__.py is a directory. - Bug #845802: Python crashes when __init__.py is a directory.
- Unicode objects received two new methods: iswide() and width(). - Unicode objects received two new methods: iswide() and width().
......
...@@ -2206,7 +2206,7 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -2206,7 +2206,7 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
{ {
PyDateTime_Date *me; PyDateTime_Date *me;
me = PyObject_New(PyDateTime_Date, type); me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
if (me != NULL) { if (me != NULL) {
char *pdata = PyString_AS_STRING(state); char *pdata = PyString_AS_STRING(state);
memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE); memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
...@@ -3049,8 +3049,7 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -3049,8 +3049,7 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
} }
} }
aware = (char)(tzinfo != Py_None); aware = (char)(tzinfo != Py_None);
me = (PyDateTime_Time *) time_alloc(&PyDateTime_TimeType, me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
aware);
if (me != NULL) { if (me != NULL) {
char *pdata = PyString_AS_STRING(state); char *pdata = PyString_AS_STRING(state);
...@@ -3572,9 +3571,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) ...@@ -3572,9 +3571,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
} }
} }
aware = (char)(tzinfo != Py_None); aware = (char)(tzinfo != Py_None);
me = (PyDateTime_DateTime *) datetime_alloc( me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
&PyDateTime_DateTimeType,
aware);
if (me != NULL) { if (me != NULL) {
char *pdata = PyString_AS_STRING(state); char *pdata = PyString_AS_STRING(state);
......
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