https://github.com/python/cpython/commit/3e4362812ee8b659d54ec7a5f9d3289de2a54d8b
commit: 3e4362812ee8b659d54ec7a5f9d3289de2a54d8b
branch: 3.13
author: Brian Schubert <[email protected]>
committer: ericsnowcurrently <[email protected]>
date: 2025-06-24T16:23:26-06:00
summary:

[3.13] gh-135855: Raise TypeError When Passing Non-dict Object to 
`_interpreters.set___main___attrs` (gh-135903)

(cherry picked from commit 4e6f0d116e, AKA gh-135856)

files:
A Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst
M Lib/test/test__interpreters.py
M Modules/_interpretersmodule.c
M Python/crossinterp.c

diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py
index 3de774ae8b012e..6fb2bc24fa3ea4 100644
--- a/Lib/test/test__interpreters.py
+++ b/Lib/test/test__interpreters.py
@@ -567,6 +567,22 @@ def test_signatures(self):
             _interpreters.run_string(self.id, 'a', shared=1)
         with self.assertRaisesRegex(TypeError, msg):
             _interpreters.run_func(self.id, lambda: None, shared=1)
+        # See https://github.com/python/cpython/issues/135855
+        msg = r'_interpreters.set___main___attrs\(\) argument 2 must be dict, 
not int'
+        with self.assertRaisesRegex(TypeError, msg):
+            _interpreters.set___main___attrs(self.id, 1)
+
+    def test_invalid_shared_none(self):
+        msg = "expected 'shared' to be a dict"
+        with self.assertRaisesRegex(TypeError, msg):
+            _interpreters.exec(self.id, 'a', shared=None)
+        with self.assertRaisesRegex(TypeError, msg):
+            _interpreters.run_string(self.id, 'a', shared=None)
+        with self.assertRaisesRegex(TypeError, msg):
+            _interpreters.run_func(self.id, lambda: None, shared=None)
+        msg = "must be dict, not None"
+        with self.assertRaisesRegex(TypeError, msg):
+            _interpreters.set___main___attrs(self.id, None)
 
     def test_invalid_shared_encoding(self):
         # See https://github.com/python/cpython/issues/127196
diff --git 
a/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst 
b/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst
new file mode 100644
index 00000000000000..fcf495bdceb168
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-06-23-10-19-11.gh-issue-135855.-J0AGF.rst
@@ -0,0 +1,3 @@
+Raise :exc:`TypeError` instead of :exc:`SystemError` when
+:func:`!_interpreters.set___main___attrs` is passed a non-dict object.
+Patch by Brian Schubert.
diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c
index 8f7106b6f1ac2a..a8fbf987ab18b3 100644
--- a/Modules/_interpretersmodule.c
+++ b/Modules/_interpretersmodule.c
@@ -811,8 +811,8 @@ interp_set___main___attrs(PyObject *self, PyObject *args, 
PyObject *kwargs)
     PyObject *id, *updates;
     int restricted = 0;
     if (!PyArg_ParseTupleAndKeywords(args, kwargs,
-                                     "OO|$p:" MODULE_NAME_STR 
".set___main___attrs",
-                                     kwlist, &id, &updates, &restricted))
+                                     "OO!|$p:" MODULE_NAME_STR 
".set___main___attrs",
+                                     kwlist, &id, &PyDict_Type, &updates, 
&restricted))
     {
         return NULL;
     }
@@ -826,16 +826,14 @@ interp_set___main___attrs(PyObject *self, PyObject *args, 
PyObject *kwargs)
     }
 
     // Check the updates.
-    if (updates != Py_None) {
-        Py_ssize_t size = PyObject_Size(updates);
-        if (size < 0) {
-            return NULL;
-        }
-        if (size == 0) {
-            PyErr_SetString(PyExc_ValueError,
-                            "arg 2 must be a non-empty mapping");
-            return NULL;
-        }
+    Py_ssize_t size = PyDict_Size(updates);
+    if (size < 0) {
+        return NULL;
+    }
+    if (size == 0) {
+        PyErr_SetString(PyExc_ValueError,
+                        "arg 2 must be a non-empty dict");
+        return NULL;
     }
 
     _PyXI_session session = {0};
diff --git a/Python/crossinterp.c b/Python/crossinterp.c
index ac379a1ad0fb6d..8382d8b95e071c 100644
--- a/Python/crossinterp.c
+++ b/Python/crossinterp.c
@@ -1704,6 +1704,7 @@ _PyXI_Enter(_PyXI_session *session,
     // Convert the attrs for cross-interpreter use.
     _PyXI_namespace *sharedns = NULL;
     if (nsupdates != NULL) {
+        assert(PyDict_Check(nsupdates));
         sharedns = _PyXI_NamespaceFromDict(nsupdates, NULL);
         if (sharedns == NULL && PyErr_Occurred()) {
             assert(session->error == NULL);

_______________________________________________
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