SF bug #761337: datetime.strftime fails on trivial format string

The interning of short strings violates the refcnt==1 assumption for
_PyString_Resize().

A simple fix is to boost the initial value of "totalnew" by 1.
Combined with an NULL argument to PyString_FromStringAndSize(),
this assures that resulting format string is not interned.
This will remain true even if the implementation of
PyString_FromStringAndSize() changes because only the uninitialized
strings that can be interned are those of zero length.

Added a test case.
This commit is contained in:
Raymond Hettinger 2003-06-27 08:14:17 +00:00
parent df9eff061e
commit f69d9f6818
2 changed files with 2 additions and 1 deletions

View File

@ -831,6 +831,7 @@ class TestDate(HarmlessMixedComparison):
def test_strftime(self): def test_strftime(self):
t = self.theclass(2005, 3, 2) t = self.theclass(2005, 3, 2)
self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05") self.assertEqual(t.strftime("m:%m d:%d y:%y"), "m:03 d:02 y:05")
self.assertEqual(t.strftime(""), "") # SF bug #761337
self.assertRaises(TypeError, t.strftime) # needs an arg self.assertRaises(TypeError, t.strftime) # needs an arg
self.assertRaises(TypeError, t.strftime, "one", "two") # too many args self.assertRaises(TypeError, t.strftime, "one", "two") # too many args

View File

@ -1175,7 +1175,7 @@ wrap_strftime(PyObject *object, PyObject *format, PyObject *timetuple,
* a new format. Since computing the replacements for those codes * a new format. Since computing the replacements for those codes
* is expensive, don't unless they're actually used. * is expensive, don't unless they're actually used.
*/ */
totalnew = PyString_Size(format); /* realistic if no %z/%Z */ totalnew = PyString_Size(format) + 1; /* realistic if no %z/%Z */
newfmt = PyString_FromStringAndSize(NULL, totalnew); newfmt = PyString_FromStringAndSize(NULL, totalnew);
if (newfmt == NULL) goto Done; if (newfmt == NULL) goto Done;
pnew = PyString_AsString(newfmt); pnew = PyString_AsString(newfmt);