Fix the refleak in strftime when converting a %Z with a user defined tzinfo.

I inverted some of the conditionals to reduce indent levels.  Hopefully
this makes it a little easier to read.

This code caused the leak:

    class FixedOffset(datetime.tzinfo):
        def tzname(self, dt): return "UTC"

    datetime.time(12, 47, tzinfo=FixedOffset()).strftime('%Z')

This code is very tricky and I'm not positive it works.  However,
it neither crashes nor leaks.
This commit is contained in:
Neal Norwitz 2007-08-12 04:32:26 +00:00
parent cbbe98f04f
commit aea70e03c4
1 changed files with 39 additions and 32 deletions

View File

@ -1131,44 +1131,51 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
static PyObject * static PyObject *
make_Zreplacement(PyObject *object, PyObject *tzinfoarg) make_Zreplacement(PyObject *object, PyObject *tzinfoarg)
{ {
PyObject *temp;
PyObject *tzinfo = get_tzinfo_member(object); PyObject *tzinfo = get_tzinfo_member(object);
PyObject *Zreplacement = PyString_FromString(""); PyObject *Zreplacement = PyString_FromString("");
if (Zreplacement == NULL) if (Zreplacement == NULL)
return NULL; return NULL;
if (tzinfo != Py_None && tzinfo != NULL) { if (tzinfo == Py_None || tzinfo == NULL)
PyObject *temp; return Zreplacement;
assert(tzinfoarg != NULL);
temp = call_tzname(tzinfo, tzinfoarg); assert(tzinfoarg != NULL);
if (temp == NULL) temp = call_tzname(tzinfo, tzinfoarg);
goto Error; if (temp == NULL)
if (temp != Py_None) { goto Error;
assert(PyUnicode_Check(temp)); if (temp == Py_None) {
/* Since the tzname is getting stuffed into the Py_DECREF(temp);
* format, we have to double any % signs so that return Zreplacement;
* strftime doesn't treat them as format codes. }
*/
assert(PyUnicode_Check(temp));
/* Since the tzname is getting stuffed into the
* format, we have to double any % signs so that
* strftime doesn't treat them as format codes.
*/
Py_DECREF(Zreplacement);
Zreplacement = PyObject_CallMethod(temp, "replace", "ss", "%", "%%");
Py_DECREF(temp);
if (Zreplacement == NULL)
return NULL;
if (PyUnicode_Check(Zreplacement)) {
/* XXX(nnorwitz): this is really convoluted, is it correct? */
PyObject *Zreplacement2 =
_PyUnicode_AsDefaultEncodedString(Zreplacement, NULL);
if (Zreplacement2 == NULL)
return NULL;
Py_INCREF(Zreplacement2);
/* Zreplacement is owned, but Zreplacement2 is borrowed.
If they are different, we have to release Zreplacement. */
if (Zreplacement != Zreplacement2) {
Py_DECREF(Zreplacement); Py_DECREF(Zreplacement);
Zreplacement = PyObject_CallMethod(temp, "replace",
"ss", "%", "%%");
Py_DECREF(temp);
if (Zreplacement == NULL)
return NULL;
if (PyUnicode_Check(Zreplacement)) {
Zreplacement =
_PyUnicode_AsDefaultEncodedString(
Zreplacement, NULL);
if (Zreplacement == NULL)
return NULL;
Py_INCREF(Zreplacement);
}
if (!PyString_Check(Zreplacement)) {
PyErr_SetString(PyExc_TypeError,
"tzname.replace() did not return a string");
goto Error;
}
} }
else Zreplacement = Zreplacement2;
Py_DECREF(temp); }
if (!PyString_Check(Zreplacement)) {
PyErr_SetString(PyExc_TypeError,
"tzname.replace() did not return a string");
goto Error;
} }
return Zreplacement; return Zreplacement;