mirror of https://github.com/python/cpython
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:
parent
cbbe98f04f
commit
aea70e03c4
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue