From 943861f09ab6bffcd1d97efcd0dd6c87c7f26800 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 4 May 2017 06:50:43 +0300 Subject: [PATCH] [3.5] bpo-30184: Add tests for invalid use of PyArg_ParseTupleAndKeywords. (GH-1316). (#1442) (cherry picked from commit 5f161fd86dd5bb936a1a2a13391b13b7e59ec201) --- Lib/test/test_capi.py | 34 +++++++++++++++++++++++++++------- Modules/_testcapimodule.c | 4 ++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 042e5aaae3..f4048583ed 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -487,9 +487,8 @@ class SkipitemTest(unittest.TestCase): # test the format unit when not skipped format = c + "i" try: - # (note: the format string must be bytes!) _testcapi.parse_tuple_and_keywords(tuple_1, dict_b, - format.encode("ascii"), keywords) + format, keywords) when_not_skipped = False except TypeError as e: s = "argument 1 (impossible)" @@ -501,7 +500,7 @@ class SkipitemTest(unittest.TestCase): optional_format = "|" + format try: _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b, - optional_format.encode("ascii"), keywords) + optional_format, keywords) when_skipped = False except RuntimeError as e: s = "impossible: '{}'".format(format) @@ -514,15 +513,36 @@ class SkipitemTest(unittest.TestCase): self.assertIs(when_skipped, when_not_skipped, message) def test_parse_tuple_and_keywords(self): - # parse_tuple_and_keywords error handling tests + # Test handling errors in the parse_tuple_and_keywords helper itself self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords, (), {}, 42, []) self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, b'', 42) + (), {}, '', 42) self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, b'', [''] * 42) + (), {}, '', [''] * 42) self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords, - (), {}, b'', [42]) + (), {}, '', [42]) + + def test_bad_use(self): + # Test handling invalid format and keywords in + # PyArg_ParseTupleAndKeywords() + self.assertRaises((TypeError, SystemError), _testcapi.parse_tuple_and_keywords, + (1,), {}, '||O', ['a']) + self.assertRaises((RuntimeError, SystemError), _testcapi.parse_tuple_and_keywords, + (1, 2), {}, '|O|O', ['a', 'b']) + self.assertRaises((TypeError, SystemError), _testcapi.parse_tuple_and_keywords, + (), {'a': 1}, '$$O', ['a']) + self.assertRaises((RuntimeError, SystemError), _testcapi.parse_tuple_and_keywords, + (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b']) + self.assertRaises((TypeError, SystemError), _testcapi.parse_tuple_and_keywords, + (), {'a': 1}, '$|O', ['a']) + self.assertRaises((RuntimeError, SystemError), _testcapi.parse_tuple_and_keywords, + (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b']) + self.assertRaises((RuntimeError, SystemError), _testcapi.parse_tuple_and_keywords, + (1,), {}, '|O', ['a', 'b']) + self.assertRaises((RuntimeError, SystemError), _testcapi.parse_tuple_and_keywords, + (1,), {}, '|OO', ['a']) + @unittest.skipUnless(threading, 'Threading required for this test.') class TestThreadState(unittest.TestCase): diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 060a92da4b..fabcaabe80 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1548,7 +1548,7 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args) { PyObject *sub_args; PyObject *sub_kwargs; - char *sub_format; + const char *sub_format; PyObject *sub_keywords; Py_ssize_t i, size; @@ -1561,7 +1561,7 @@ parse_tuple_and_keywords(PyObject *self, PyObject *args) double buffers[8][4]; /* double ensures alignment where necessary */ - if (!PyArg_ParseTuple(args, "OOyO:parse_tuple_and_keywords", + if (!PyArg_ParseTuple(args, "OOsO:parse_tuple_and_keywords", &sub_args, &sub_kwargs, &sub_format, &sub_keywords)) return NULL; -- 2.50.1