summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_functools.py26
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_functoolsmodule.c5
4 files changed, 34 insertions, 1 deletions
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 612ca17a60..29ea493622 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -403,6 +403,32 @@ class TestPartialC(TestPartial, unittest.TestCase):
else:
self.fail('partial object allowed __dict__ to be deleted')
+ def test_manually_adding_non_string_keyword(self):
+ p = self.partial(capture)
+ # Adding a non-string/unicode keyword to partial kwargs
+ p.keywords[1234] = 'value'
+ r = repr(p)
+ self.assertIn('1234', r)
+ self.assertIn("'value'", r)
+ with self.assertRaises(TypeError):
+ p()
+
+ def test_keystr_replaces_value(self):
+ p = self.partial(capture)
+
+ class MutatesYourDict(object):
+ def __str__(self):
+ p.keywords[self] = ['sth2']
+ return 'astr'
+
+ # Raplacing the value during key formatting should keep the original
+ # value alive (at least long enough).
+ p.keywords[MutatesYourDict()] = ['sth']
+ r = repr(p)
+ self.assertIn('astr', r)
+ self.assertIn("['sth']", r)
+
+
class TestPartialPy(TestPartial, unittest.TestCase):
partial = py_functools.partial
diff --git a/Misc/ACKS b/Misc/ACKS
index b7f1282c69..c99aeaa335 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1374,6 +1374,7 @@ Federico Schwindt
Barry Scott
Steven Scott
Nick Seidenman
+Michael Seifert
Žiga Seilnacht
Yury Selivanov
Fred Sells
diff --git a/Misc/NEWS b/Misc/NEWS
index b2a1a6eaee..2f7bd7ac7b 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -281,6 +281,9 @@ Extension Modules
Library
-------
+- bpo-29800: Fix crashes in partial.__repr__ if the keys of partial.keywords
+ are not strings. Patch by Michael Seifert.
+
- bpo-8256: Fixed possible failing or crashing input() if attributes "encoding"
or "errors" of sys.stdin or sys.stdout are not set or are not strings.
diff --git a/Modules/_functoolsmodule.c b/Modules/_functoolsmodule.c
index f2af4ab462..592edbb614 100644
--- a/Modules/_functoolsmodule.c
+++ b/Modules/_functoolsmodule.c
@@ -297,8 +297,11 @@ partial_repr(partialobject *pto)
/* Pack keyword arguments */
assert (PyDict_Check(pto->kw));
for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) {
- Py_SETREF(arglist, PyUnicode_FromFormat("%U, %U=%R", arglist,
+ /* Prevent key.__str__ from deleting the value. */
+ Py_INCREF(value);
+ Py_SETREF(arglist, PyUnicode_FromFormat("%U, %S=%R", arglist,
key, value));
+ Py_DECREF(value);
if (arglist == NULL)
goto done;
}