]> granicus.if.org Git - python/commitdiff
[3.6] bpo-30184: Add tests for invalid use of PyArg_ParseTupleAndKeywords. (GH-1316...
authorSerhiy Storchaka <storchaka@gmail.com>
Thu, 4 May 2017 03:50:28 +0000 (06:50 +0300)
committerGitHub <noreply@github.com>
Thu, 4 May 2017 03:50:28 +0000 (06:50 +0300)
(cherry picked from commit 5f161fd86dd5bb936a1a2a13391b13b7e59ec201)

Lib/test/test_capi.py
Modules/_testcapimodule.c

index 08aa3ffdf6b4f1e923eafa69ffd297b6d3886428..216851c2d36c8b429626f2d5976f0973338f4e06 100644 (file)
@@ -490,9 +490,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 SystemError as e:
                 s = "argument 1 (impossible<bad format char>)"
@@ -504,7 +503,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 SystemError as e:
                 s = "impossible<bad format char>: '{}'".format(format)
@@ -517,40 +516,64 @@ 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(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (1,), {}, '||O', ['a'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (1, 2), {}, '|O|O', ['a', 'b'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {'a': 1}, '$$O', ['a'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {'a': 1, 'b': 2}, '$O$O', ['a', 'b'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {'a': 1}, '$|O', ['a'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {'a': 1, 'b': 2}, '$O|O', ['a', 'b'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (1,), {}, '|O', ['a', 'b'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (1,), {}, '|OO', ['a'])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {}, '|$O', [''])
+        self.assertRaises(SystemError, _testcapi.parse_tuple_and_keywords,
+                          (), {}, '|OO', ['a', ''])
 
     def test_positional_only(self):
         parse = _testcapi.parse_tuple_and_keywords
 
-        parse((1, 2, 3), {}, b'OOO', ['', '', 'a'])
-        parse((1, 2), {'a': 3}, b'OOO', ['', '', 'a'])
+        parse((1, 2, 3), {}, 'OOO', ['', '', 'a'])
+        parse((1, 2), {'a': 3}, 'OOO', ['', '', 'a'])
         with self.assertRaisesRegex(TypeError,
                r'Function takes at least 2 positional arguments \(1 given\)'):
-            parse((1,), {'a': 3}, b'OOO', ['', '', 'a'])
-        parse((1,), {}, b'O|OO', ['', '', 'a'])
+            parse((1,), {'a': 3}, 'OOO', ['', '', 'a'])
+        parse((1,), {}, 'O|OO', ['', '', 'a'])
         with self.assertRaisesRegex(TypeError,
                r'Function takes at least 1 positional arguments \(0 given\)'):
-            parse((), {}, b'O|OO', ['', '', 'a'])
-        parse((1, 2), {'a': 3}, b'OO$O', ['', '', 'a'])
+            parse((), {}, 'O|OO', ['', '', 'a'])
+        parse((1, 2), {'a': 3}, 'OO$O', ['', '', 'a'])
         with self.assertRaisesRegex(TypeError,
                r'Function takes exactly 2 positional arguments \(1 given\)'):
-            parse((1,), {'a': 3}, b'OO$O', ['', '', 'a'])
-        parse((1,), {}, b'O|O$O', ['', '', 'a'])
+            parse((1,), {'a': 3}, 'OO$O', ['', '', 'a'])
+        parse((1,), {}, 'O|O$O', ['', '', 'a'])
         with self.assertRaisesRegex(TypeError,
                r'Function takes at least 1 positional arguments \(0 given\)'):
-            parse((), {}, b'O|O$O', ['', '', 'a'])
+            parse((), {}, 'O|O$O', ['', '', 'a'])
         with self.assertRaisesRegex(SystemError, r'Empty parameter name after \$'):
-            parse((1,), {}, b'O|$OO', ['', '', 'a'])
+            parse((1,), {}, 'O|$OO', ['', '', 'a'])
         with self.assertRaisesRegex(SystemError, 'Empty keyword'):
-            parse((1,), {}, b'O|OO', ['', 'a', ''])
+            parse((1,), {}, 'O|OO', ['', 'a', ''])
 
 
 @unittest.skipUnless(threading, 'Threading required for this test.')
index b25f4434ffa35c4bc35a95e38eb26cdf41119150..c76eefab4e80cfc6a678344db747a527ad512693 100644 (file)
@@ -1571,7 +1571,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;
@@ -1584,7 +1584,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;