From 70533e28ad75fe60ba2d0bb11124a3dc69b16bb7 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Sat, 1 Feb 2003 04:40:04 +0000 Subject: [PATCH] New functions alloc_{time,datetime}. Got rid of all setstate-like functions. Reworked {time,datetime}_new() to do what their corresponding setstates used to do in their state-tuple-input paths, but directly, without constructing an object with throwaway state first. Tightened the "is this a state tuple input?" paths to check the presumed state string-length too, and to raise an exception if the optional second state element isn't a tzinfo instance (IOW, check these paths for type errors as carefully as the normal paths). --- Modules/datetimemodule.c | 291 +++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 168 deletions(-) diff --git a/Modules/datetimemodule.c b/Modules/datetimemodule.c index ba2b737d493..944c0bbea92 100644 --- a/Modules/datetimemodule.c +++ b/Modules/datetimemodule.c @@ -1224,6 +1224,42 @@ diff_to_bool(int diff, int op) return result; } +/* --------------------------------------------------------------------------- + * Basic object allocation. These allocate Python objects of the right + * size and type, and do the Python object-initialization bit. If there's + * not enough memory, they return NULL after setting MemoryError. All + * data members remain uninitialized trash. + */ +static PyDateTime_Time * +alloc_time(int aware) +{ + PyDateTime_Time *self; + + self = (PyDateTime_Time *) + PyObject_MALLOC(aware ? + sizeof(PyDateTime_Time) : + sizeof(_PyDateTime_BaseTime)); + if (self == NULL) + return (PyDateTime_Time *)PyErr_NoMemory(); + PyObject_INIT(self, &PyDateTime_TimeType); + return self; +} + +static PyDateTime_DateTime * +alloc_datetime(int aware) +{ + PyDateTime_DateTime *self; + + self = (PyDateTime_DateTime *) + PyObject_MALLOC(aware ? + sizeof(PyDateTime_DateTime) : + sizeof(_PyDateTime_BaseDateTime)); + if (self == NULL) + return (PyDateTime_DateTime *)PyErr_NoMemory(); + PyObject_INIT(self, &PyDateTime_DateTimeType); + return self; +} + /* --------------------------------------------------------------------------- * Helpers for setting object fields. These work on pointers to the * appropriate base class. @@ -1263,22 +1299,20 @@ new_datetime(int year, int month, int day, int hour, int minute, PyDateTime_DateTime *self; char aware = tzinfo != Py_None; - self = (PyDateTime_DateTime *)PyObject_MALLOC(aware ? - sizeof(PyDateTime_DateTime) : - sizeof(_PyDateTime_BaseDateTime)); - if (self == NULL) - return PyErr_NoMemory(); - self->hastzinfo = aware; - set_date_fields((PyDateTime_Date *)self, year, month, day); - DATE_SET_HOUR(self, hour); - DATE_SET_MINUTE(self, minute); - DATE_SET_SECOND(self, second); - DATE_SET_MICROSECOND(self, usecond); - if (aware) { - Py_INCREF(tzinfo); - self->tzinfo = tzinfo; + self = alloc_datetime(aware); + if (self != NULL) { + self->hastzinfo = aware; + set_date_fields((PyDateTime_Date *)self, year, month, day); + DATE_SET_HOUR(self, hour); + DATE_SET_MINUTE(self, minute); + DATE_SET_SECOND(self, second); + DATE_SET_MICROSECOND(self, usecond); + if (aware) { + Py_INCREF(tzinfo); + self->tzinfo = tzinfo; + } } - return (PyObject *)PyObject_INIT(self, &PyDateTime_DateTimeType); + return (PyObject *)self; } /* Create a time instance with no range checking. */ @@ -1288,22 +1322,20 @@ new_time(int hour, int minute, int second, int usecond, PyObject *tzinfo) PyDateTime_Time *self; char aware = tzinfo != Py_None; - self = (PyDateTime_Time *)PyObject_MALLOC(aware ? - sizeof(PyDateTime_Time) : - sizeof(_PyDateTime_BaseTime)); - if (self == NULL) - return PyErr_NoMemory(); - self->hastzinfo = aware; - self->hashcode = -1; - TIME_SET_HOUR(self, hour); - TIME_SET_MINUTE(self, minute); - TIME_SET_SECOND(self, second); - TIME_SET_MICROSECOND(self, usecond); - if (aware) { - Py_INCREF(tzinfo); - self->tzinfo = tzinfo; + self = alloc_time(aware); + if (self != NULL) { + self->hastzinfo = aware; + self->hashcode = -1; + TIME_SET_HOUR(self, hour); + TIME_SET_MINUTE(self, minute); + TIME_SET_SECOND(self, second); + TIME_SET_MICROSECOND(self, usecond); + if (aware) { + Py_INCREF(tzinfo); + self->tzinfo = tzinfo; + } } - return (PyObject *)PyObject_INIT(self, &PyDateTime_TimeType); + return (PyObject *)self; } /* Create a timedelta instance. Normalize the members iff normalize is @@ -2108,60 +2140,29 @@ static PyGetSetDef date_getset[] = { static char *date_kws[] = {"year", "month", "day", NULL}; -/* __setstate__ isn't exposed. */ -static PyObject * -date_setstate(PyDateTime_Date *self, PyObject *arg) -{ - PyObject *state; - int len; - unsigned char *pdata; - - if (!PyTuple_Check(arg) || PyTuple_GET_SIZE(arg) != 1) - goto error; - state = PyTuple_GET_ITEM(arg, 0); - if (!PyString_Check(state)) - goto error; - - len = PyString_Size(state); - if (len != _PyDateTime_DATE_DATASIZE) - goto error; - - pdata = (unsigned char*)PyString_AsString(state); - memcpy(self->data, pdata, _PyDateTime_DATE_DATASIZE); - self->hashcode = -1; - - Py_INCREF(Py_None); - return Py_None; - error: - PyErr_SetString(PyExc_TypeError, - "bad argument to date.__setstate__"); - return NULL; -} - static PyObject * date_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *self = NULL; + PyObject *state; int year; int month; int day; /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) == 1 && - PyString_Check(PyTuple_GET_ITEM(args, 0))) + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_DATE_DATASIZE) { - self = new_date(1, 1, 1); - if (self != NULL) { - PyObject *res = date_setstate( - (PyDateTime_Date *)self, args); - if (res == Py_None) - Py_DECREF(res); - else { - Py_DECREF(self); - self = NULL; - } + PyDateTime_Date *me; + + me = PyObject_New(PyDateTime_Date, &PyDateTime_DateType); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + memcpy(me->data, pdata, _PyDateTime_DATE_DATASIZE); + me->hashcode = -1; } - return self; + return (PyObject *)me; } if (PyArg_ParseTupleAndKeywords(args, kw, "iii", date_kws, @@ -2969,46 +2970,11 @@ static PyGetSetDef time_getset[] = { static char *time_kws[] = {"hour", "minute", "second", "microsecond", "tzinfo", NULL}; -/* __setstate__ isn't exposed. */ -static PyObject * -time_setstate(PyDateTime_Time *self, PyObject *state) -{ - PyObject *basestate; - PyObject *tzinfo = Py_None; - - if (! PyArg_ParseTuple(state, "O!|O:__setstate__", - &PyString_Type, &basestate, - &tzinfo)) - return NULL; - if (PyString_Size(basestate) != _PyDateTime_TIME_DATASIZE || - check_tzinfo_subclass(tzinfo) < 0) { - PyErr_SetString(PyExc_TypeError, - "bad argument to time.__setstate__"); - return NULL; - } - if (tzinfo != Py_None && ! HASTZINFO(self)) { - PyErr_SetString(PyExc_ValueError, "time.__setstate__ can't " - "add a non-None tzinfo to a time object that " - "doesn't have one already"); - return NULL; - } - memcpy((char *)self->data, - PyString_AsString(basestate), - _PyDateTime_TIME_DATASIZE); - self->hashcode = -1; - if (HASTZINFO(self)) { - Py_INCREF(tzinfo); - Py_XDECREF(self->tzinfo); - self->tzinfo = tzinfo; - } - Py_INCREF(Py_None); - return Py_None; -} - static PyObject * time_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *self = NULL; + PyObject *state; int hour = 0; int minute = 0; int second = 0; @@ -3018,22 +2984,34 @@ time_new(PyTypeObject *type, PyObject *args, PyObject *kw) /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2 && - PyString_Check(PyTuple_GET_ITEM(args, 0))) + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_TIME_DATASIZE) { - if (PyTuple_GET_SIZE(args) == 2) + PyDateTime_Time *me; + char aware; + + if (PyTuple_GET_SIZE(args) == 2) { tzinfo = PyTuple_GET_ITEM(args, 1); - self = new_time(0, 0, 0, 0, tzinfo); - if (self != NULL) { - PyObject *res = time_setstate( - (PyDateTime_Time *)self, args); - if (res == Py_None) - Py_DECREF(res); - else { - Py_DECREF(self); - self = NULL; + if (check_tzinfo_subclass(tzinfo) < 0) { + PyErr_SetString(PyExc_TypeError, "bad " + "tzinfo state arg"); + return NULL; } } - return self; + aware = (char)(tzinfo != Py_None); + me = alloc_time(aware); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + + memcpy(me->data, pdata, _PyDateTime_TIME_DATASIZE); + me->hashcode = -1; + me->hastzinfo = aware; + if (aware) { + Py_INCREF(tzinfo); + me->tzinfo = tzinfo; + } + } + return (PyObject *)me; } if (PyArg_ParseTupleAndKeywords(args, kw, "|iiiiO", time_kws, @@ -3508,46 +3486,11 @@ static char *datetime_kws[] = { "microsecond", "tzinfo", NULL }; -/* __setstate__ isn't exposed. */ -static PyObject * -datetime_setstate(PyDateTime_DateTime *self, PyObject *state) -{ - PyObject *basestate; - PyObject *tzinfo = Py_None; - - if (! PyArg_ParseTuple(state, "O!|O:__setstate__", - &PyString_Type, &basestate, - &tzinfo)) - return NULL; - if (PyString_Size(basestate) != _PyDateTime_DATETIME_DATASIZE || - check_tzinfo_subclass(tzinfo) < 0) { - PyErr_SetString(PyExc_TypeError, - "bad argument to datetime.__setstate__"); - return NULL; - } - if (tzinfo != Py_None && ! HASTZINFO(self)) { - PyErr_SetString(PyExc_ValueError, "datetime.__setstate__ " - "can't add a non-None tzinfo to a datetime " - "object that doesn't have one already"); - return NULL; - } - memcpy((char *)self->data, - PyString_AsString(basestate), - _PyDateTime_DATETIME_DATASIZE); - self->hashcode = -1; - if (HASTZINFO(self)) { - Py_INCREF(tzinfo); - Py_XDECREF(self->tzinfo); - self->tzinfo = tzinfo; - } - Py_INCREF(Py_None); - return Py_None; -} - static PyObject * datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) { PyObject *self = NULL; + PyObject *state; int year; int month; int day; @@ -3560,22 +3503,34 @@ datetime_new(PyTypeObject *type, PyObject *args, PyObject *kw) /* Check for invocation from pickle with __getstate__ state */ if (PyTuple_GET_SIZE(args) >= 1 && PyTuple_GET_SIZE(args) <= 2 && - PyString_Check(PyTuple_GET_ITEM(args, 0))) + PyString_Check(state = PyTuple_GET_ITEM(args, 0)) && + PyString_GET_SIZE(state) == _PyDateTime_DATETIME_DATASIZE) { - if (PyTuple_GET_SIZE(args) == 2) + PyDateTime_DateTime *me; + char aware; + + if (PyTuple_GET_SIZE(args) == 2) { tzinfo = PyTuple_GET_ITEM(args, 1); - self = new_datetime(1, 1, 1, 0, 0, 0, 0, tzinfo); - if (self != NULL) { - PyObject *res = datetime_setstate( - (PyDateTime_DateTime *)self, args); - if (res == Py_None) - Py_DECREF(res); - else { - Py_DECREF(self); - self = NULL; + if (check_tzinfo_subclass(tzinfo) < 0) { + PyErr_SetString(PyExc_TypeError, "bad " + "tzinfo state arg"); + return NULL; } } - return self; + aware = (char)(tzinfo != Py_None); + me = alloc_datetime(aware); + if (me != NULL) { + char *pdata = PyString_AS_STRING(state); + + memcpy(me->data, pdata, _PyDateTime_DATETIME_DATASIZE); + me->hashcode = -1; + me->hastzinfo = aware; + if (aware) { + Py_INCREF(tzinfo); + me->tzinfo = tzinfo; + } + } + return (PyObject *)me; } if (PyArg_ParseTupleAndKeywords(args, kw, "iii|iiiiO", datetime_kws,