SF bug 847019 datetime.datetime initialization needs more strict checking
It's possible to create insane datetime objects by using the constructor "backdoor" inserted for fast unpickling. Doing extensive range checking would eliminate the backdoor's purpose (speed), but at least a little checking can stop honest mistakes. Bugfix candidate.
This commit is contained in:
parent
6fce78e07f
commit
3f60629242
|
@ -1029,6 +1029,26 @@ 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_backdoor_resistance(self):
|
||||||
|
# For fast unpickling, the constructor accepts a pickle string.
|
||||||
|
# This is a low-overhead backdoor. A user can (by intent or
|
||||||
|
# mistake) pass a string directly, which (if it's the right length)
|
||||||
|
# will get treated like a pickle, and bypass the normal sanity
|
||||||
|
# checks in the constructor. This can create insane objects.
|
||||||
|
# The constructor doesn't want to burn the time to validate all
|
||||||
|
# fields, but does check the month field. This stops, e.g.,
|
||||||
|
# datetime.datetime('1995-03-25') from yielding an insane object.
|
||||||
|
base = '1995-03-25'
|
||||||
|
if not issubclass(self.theclass, datetime):
|
||||||
|
base = base[:4]
|
||||||
|
for month_byte in '9', chr(0), chr(13), '\xff':
|
||||||
|
self.assertRaises(TypeError, self.theclass,
|
||||||
|
base[:2] + month_byte + base[3:])
|
||||||
|
for ord_byte in range(1, 13):
|
||||||
|
# This shouldn't blow up because of the month byte alone. If
|
||||||
|
# the implementation changes to do more-careful checking, it may
|
||||||
|
# blow up because other fields are insane.
|
||||||
|
self.theclass(base[:2] + chr(ord_byte) + base[3:])
|
||||||
|
|
||||||
#############################################################################
|
#############################################################################
|
||||||
# datetime tests
|
# datetime tests
|
||||||
|
|
|
@ -80,6 +80,12 @@
|
||||||
*/
|
*/
|
||||||
#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
|
#define HASTZINFO(p) (((_PyDateTime_BaseTZInfo *)(p))->hastzinfo)
|
||||||
|
|
||||||
|
/* M is a char or int claiming to be a valid month. The macro is equivalent
|
||||||
|
* to the two-sided Python test
|
||||||
|
* 1 <= M <= 12
|
||||||
|
*/
|
||||||
|
#define MONTH_IS_SANE(M) ((unsigned int)(M) - 1 < 12)
|
||||||
|
|
||||||
/* Forward declarations. */
|
/* Forward declarations. */
|
||||||
static PyTypeObject PyDateTime_DateType;
|
static PyTypeObject PyDateTime_DateType;
|
||||||
static PyTypeObject PyDateTime_DateTimeType;
|
static PyTypeObject PyDateTime_DateTimeType;
|
||||||
|
@ -2195,7 +2201,8 @@ date_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
/* Check for invocation from pickle with __getstate__ state */
|
/* Check for invocation from pickle with __getstate__ state */
|
||||||
if (PyTuple_GET_SIZE(args) == 1 &&
|
if (PyTuple_GET_SIZE(args) == 1 &&
|
||||||
PyString_Check(state = PyTuple_GET_ITEM(args, 0)) &&
|
PyString_Check(state = PyTuple_GET_ITEM(args, 0)) &&
|
||||||
PyString_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE)
|
PyString_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE &&
|
||||||
|
MONTH_IS_SANE(PyString_AS_STRING(state)[2]))
|
||||||
{
|
{
|
||||||
PyDateTime_Date *me;
|
PyDateTime_Date *me;
|
||||||
|
|
||||||
|
@ -3550,7 +3557,8 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
||||||
if (PyTuple_GET_SIZE(args) >= 1 &&
|
if (PyTuple_GET_SIZE(args) >= 1 &&
|
||||||
PyTuple_GET_SIZE(args) <= 2 &&
|
PyTuple_GET_SIZE(args) <= 2 &&
|
||||||
PyString_Check(state = PyTuple_GET_ITEM(args, 0)) &&
|
PyString_Check(state = PyTuple_GET_ITEM(args, 0)) &&
|
||||||
PyString_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE)
|
PyString_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE &&
|
||||||
|
MONTH_IS_SANE(PyString_AS_STRING(state)[2]))
|
||||||
{
|
{
|
||||||
PyDateTime_DateTime *me;
|
PyDateTime_DateTime *me;
|
||||||
char aware;
|
char aware;
|
||||||
|
|
Loading…
Reference in New Issue