https://github.com/python/cpython/commit/7d2ffada0a6490e6839697f729bcd80380e9f561
commit: 7d2ffada0a6490e6839697f729bcd80380e9f561
branch: main
author: NGRsoftlab <[email protected]>
committer: serhiy-storchaka <[email protected]>
date: 2024-05-02T16:43:03+03:00
summary:

gh-116180: Check the globals argument in PyRun_* C API (GH-116637)

It used to crash when passing NULL or non-dict as globals.
Now it sets a SystemError.

files:
M Lib/test/test_capi/test_run.py
M Python/pythonrun.c

diff --git a/Lib/test/test_capi/test_run.py b/Lib/test/test_capi/test_run.py
index 3a390273ec21ad..894f66b437a39c 100644
--- a/Lib/test/test_capi/test_run.py
+++ b/Lib/test/test_capi/test_run.py
@@ -11,6 +11,10 @@
 Py_eval_input = _testcapi.Py_eval_input
 
 
+class DictSubclass(dict):
+    pass
+
+
 class CAPITest(unittest.TestCase):
     # TODO: Test the following functions:
     #
@@ -50,15 +54,19 @@ def run(s, *args):
         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 @@ def run(*args):
         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')
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 2970248da13705..31213aec3cd9c3 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -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);

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]

Reply via email to