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,45 +1131,52 @@ format_utcoffset(char *buf, size_t buflen, const char *sep,
static PyObject *
make_Zreplacement(PyObject *object, PyObject *tzinfoarg)
{
PyObject *temp;
PyObject *tzinfo = get_tzinfo_member(object);
PyObject *Zreplacement = PyString_FromString("");
if (Zreplacement == NULL)
return NULL;
if (tzinfo != Py_None && tzinfo != NULL) {
PyObject *temp;
if (tzinfo == Py_None || tzinfo == NULL)
return Zreplacement;
assert(tzinfoarg != NULL);
temp = call_tzname(tzinfo, tzinfoarg);
if (temp == NULL)
goto Error;
if (temp != Py_None) {
if (temp == Py_None) {
Py_DECREF(temp);
return Zreplacement;
}
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", "%", "%%");
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)
/* XXX(nnorwitz): this is really convoluted, is it correct? */
PyObject *Zreplacement2 =
_PyUnicode_AsDefaultEncodedString(Zreplacement, NULL);
if (Zreplacement2 == NULL)
return NULL;
Py_INCREF(Zreplacement);
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);
}
Zreplacement = Zreplacement2;
}
if (!PyString_Check(Zreplacement)) {
PyErr_SetString(PyExc_TypeError,
"tzname.replace() did not return a string");
goto Error;
}
}
else
Py_DECREF(temp);
}
return Zreplacement;
Error: