Skip to content

Commit 435a68e

Browse files
author
tim_one
committed
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. git-svn-id: http://svn.python.org/projects/python/trunk@36119 6015fed2-1504-0410-9fe1-9d1591cc4771
1 parent 29192fa commit 435a68e

3 files changed

Lines changed: 41 additions & 6 deletions

File tree

Lib/test/test_datetime.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,9 @@ def test_delta_non_days_ignored(self):
510510
dt2 = dt - delta
511511
self.assertEqual(dt2, dt - days)
512512

513+
class SubclassDate(date):
514+
sub_var = 1
515+
513516
class TestDate(HarmlessMixedComparison):
514517
# Tests here should pass for both dates and datetimes, except for a
515518
# few tests that TestDateTime overrides.
@@ -1029,6 +1032,15 @@ def newmeth(self, start):
10291032
self.assertEqual(dt1.toordinal(), dt2.toordinal())
10301033
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month - 7)
10311034

1035+
def test_pickling_subclass_date(self):
1036+
1037+
args = 6, 7, 23
1038+
orig = SubclassDate(*args)
1039+
for pickler, unpickler, proto in pickle_choices:
1040+
green = pickler.dumps(orig, proto)
1041+
derived = unpickler.loads(green)
1042+
self.assertEqual(orig, derived)
1043+
10321044
def test_backdoor_resistance(self):
10331045
# For fast unpickling, the constructor accepts a pickle string.
10341046
# This is a low-overhead backdoor. A user can (by intent or
@@ -1053,6 +1065,9 @@ def test_backdoor_resistance(self):
10531065
#############################################################################
10541066
# datetime tests
10551067

1068+
class SubclassDatetime(datetime):
1069+
sub_var = 1
1070+
10561071
class TestDateTime(TestDate):
10571072

10581073
theclass = datetime
@@ -1296,6 +1311,14 @@ def test_more_pickling(self):
12961311
self.assertEqual(b.month, 2)
12971312
self.assertEqual(b.day, 7)
12981313

1314+
def test_pickling_subclass_datetime(self):
1315+
args = 6, 7, 23, 20, 59, 1, 64**2
1316+
orig = SubclassDatetime(*args)
1317+
for pickler, unpickler, proto in pickle_choices:
1318+
green = pickler.dumps(orig, proto)
1319+
derived = unpickler.loads(green)
1320+
self.assertEqual(orig, derived)
1321+
12991322
def test_more_compare(self):
13001323
# The test_compare() inherited from TestDate covers the error cases.
13011324
# We just want to test lexicographic ordering on the members datetime
@@ -1500,6 +1523,9 @@ def newmeth(self, start):
15001523
self.assertEqual(dt2.newmeth(-7), dt1.year + dt1.month +
15011524
dt1.second - 7)
15021525

1526+
class SubclassTime(time):
1527+
sub_var = 1
1528+
15031529
class TestTime(HarmlessMixedComparison):
15041530

15051531
theclass = time
@@ -1700,6 +1726,14 @@ def test_pickling(self):
17001726
derived = unpickler.loads(green)
17011727
self.assertEqual(orig, derived)
17021728

1729+
def test_pickling_subclass_time(self):
1730+
args = 20, 59, 16, 64**2
1731+
orig = SubclassTime(*args)
1732+
for pickler, unpickler, proto in pickle_choices:
1733+
green = pickler.dumps(orig, proto)
1734+
derived = unpickler.loads(green)
1735+
self.assertEqual(orig, derived)
1736+
17031737
def test_bool(self):
17041738
cls = self.theclass
17051739
self.failUnless(cls(1))

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ What's New in Python 2.4 alpha 1?
1212
Core and builtins
1313
-----------------
1414

15+
- Bug #952807: Unpickling pickled instances of subclasses of
16+
datetime.date, datetime.datetime and datetime.time could yield insane
17+
objects. Thanks to Jiwon Seo for a fix.
18+
1519
- Bug #845802: Python crashes when __init__.py is a directory.
1620

1721
- Unicode objects received two new methods: iswide() and width().

Modules/datetimemodule.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2206,7 +2206,7 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
22062206
{
22072207
PyDateTime_Date *me;
22082208

2209-
me = PyObject_New(PyDateTime_Date, type);
2209+
me = (PyDateTime_Date *) (type->tp_alloc(type, 0));
22102210
if (me != NULL) {
22112211
char *pdata = PyString_AS_STRING(state);
22122212
memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE);
@@ -3049,8 +3049,7 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw)
30493049
}
30503050
}
30513051
aware = (char)(tzinfo != Py_None);
3052-
me = (PyDateTime_Time *) time_alloc(&PyDateTime_TimeType,
3053-
aware);
3052+
me = (PyDateTime_Time *) (type->tp_alloc(type, aware));
30543053
if (me != NULL) {
30553054
char *pdata = PyString_AS_STRING(state);
30563055

@@ -3572,9 +3571,7 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
35723571
}
35733572
}
35743573
aware = (char)(tzinfo != Py_None);
3575-
me = (PyDateTime_DateTime *) datetime_alloc(
3576-
&PyDateTime_DateTimeType,
3577-
aware);
3574+
me = (PyDateTime_DateTime *) (type->tp_alloc(type , aware));
35783575
if (me != NULL) {
35793576
char *pdata = PyString_AS_STRING(state);
35803577

0 commit comments

Comments
 (0)