]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-116180: Check the globals argument in PyRun_* C API (GH-116637)
authorNGRsoftlab <78017794+NGRsoftlab@users.noreply.github.com>
Thu, 2 May 2024 13:43:03 +0000 (16:43 +0300)
committerGitHub <noreply@github.com>
Thu, 2 May 2024 13:43:03 +0000 (16:43 +0300)
It used to crash when passing NULL or non-dict as globals.
Now it sets a SystemError.

Lib/test/test_capi/test_run.py
Python/pythonrun.c

index 3a390273ec21addb8a8bd7d94afa7d1ed2163f7a..894f66b437a39c2c8cefdfa1e22b08d4810a3f11 100644 (file)
@@ -11,6 +11,10 @@ Py_file_input = _testcapi.Py_file_input
 Py_eval_input = _testcapi.Py_eval_input
 
 
+class DictSubclass(dict):
+    pass
+
+
 class CAPITest(unittest.TestCase):
     # TODO: Test the following functions:
     #
@@ -50,15 +54,19 @@ class CAPITest(unittest.TestCase):
         self.assertRaises(TypeError, run, b'a\n', dict(a=1), [])
         self.assertRaises(TypeError, run, b'a\n', dict(a=1), 1)
 
+        self.assertIsNone(run(b'a\n', DictSubclass(a=1)))
+        self.assertIsNone(run(b'a\n', DictSubclass(), dict(a=1)))
+        self.assertRaises(NameError, run, b'a\n', DictSubclass())
+
         self.assertIsNone(run(b'\xc3\xa4\n', {'\xe4': 1}))
         self.assertRaises(SyntaxError, run, b'\xe4\n', {})
 
-        # CRASHES run(b'a\n', NULL)
-        # CRASHES run(b'a\n', NULL, {})
-        # CRASHES run(b'a\n', NULL, dict(a=1))
-        # CRASHES run(b'a\n', UserDict())
-        # CRASHES run(b'a\n', UserDict(), {})
-        # CRASHES run(b'a\n', UserDict(), dict(a=1))
+        self.assertRaises(SystemError, run, b'a\n', NULL)
+        self.assertRaises(SystemError, run, b'a\n', NULL, {})
+        self.assertRaises(SystemError, run, b'a\n', NULL, dict(a=1))
+        self.assertRaises(SystemError, run, b'a\n', UserDict())
+        self.assertRaises(SystemError, run, b'a\n', UserDict(), {})
+        self.assertRaises(SystemError, run, b'a\n', UserDict(), dict(a=1))
 
         # CRASHES run(NULL, {})
 
@@ -82,12 +90,16 @@ class CAPITest(unittest.TestCase):
         self.assertRaises(TypeError, run, dict(a=1), [])
         self.assertRaises(TypeError, run, dict(a=1), 1)
 
-        # CRASHES run(NULL)
-        # CRASHES run(NULL, {})
-        # CRASHES run(NULL, dict(a=1))
-        # CRASHES run(UserDict())
-        # CRASHES run(UserDict(), {})
-        # CRASHES run(UserDict(), dict(a=1))
+        self.assertIsNone(run(DictSubclass(a=1)))
+        self.assertIsNone(run(DictSubclass(), dict(a=1)))
+        self.assertRaises(NameError, run, DictSubclass())
+
+        self.assertRaises(SystemError, run, NULL)
+        self.assertRaises(SystemError, run, NULL, {})
+        self.assertRaises(SystemError, run, NULL, dict(a=1))
+        self.assertRaises(SystemError, run, UserDict())
+        self.assertRaises(SystemError, run, UserDict(), {})
+        self.assertRaises(SystemError, run, UserDict(), dict(a=1))
 
     @unittest.skipUnless(TESTFN_UNDECODABLE, 'only works if there are undecodable paths')
     @unittest.skipIf(os.name == 'nt', 'does not work on Windows')
index 2970248da1370553833a0b7efa90a0a66798bf45..31213aec3cd9c301f33523f03317133740417a1c 100644 (file)
@@ -1275,17 +1275,20 @@ run_eval_code_obj(PyThreadState *tstate, PyCodeObject *co, PyObject *globals, Py
     _PyRuntime.signals.unhandled_keyboard_interrupt = 0;
 
     /* Set globals['__builtins__'] if it doesn't exist */
-    if (globals != NULL) {
-        int has_builtins = PyDict_ContainsString(globals, "__builtins__");
-        if (has_builtins < 0) {
+    if (!globals || !PyDict_Check(globals)) {
+        PyErr_SetString(PyExc_SystemError, "globals must be a real dict");
+        return NULL;
+    }
+    int has_builtins = PyDict_ContainsString(globals, "__builtins__");
+    if (has_builtins < 0) {
+        return NULL;
+    }
+    if (!has_builtins) {
+        if (PyDict_SetItemString(globals, "__builtins__",
+                                 tstate->interp->builtins) < 0)
+        {
             return NULL;
         }
-        if (!has_builtins) {
-            if (PyDict_SetItemString(globals, "__builtins__",
-                                     tstate->interp->builtins) < 0) {
-                return NULL;
-            }
-        }
     }
 
     v = PyEval_EvalCode((PyObject*)co, globals, locals);