From 3e7c1bb5176702277b08758a7b31cb69588c8ed9 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Aug 2024 23:01:44 +0200 Subject: [PATCH] 00434: gh-122728: Fix SystemError in PyEval_GetLocals() Fix PyEval_GetLocals() to avoid SystemError ("bad argument to internal function"). Don't redefine the 'ret' variable in the if block. Add an unit test on PyEval_GetLocals(). (cherry picked from commit 4767a6e31c0550836b2af45d27e374e721f0c4e6) --- Lib/test/test_capi/test_misc.py | 13 +++++++++++++ .../2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst | 2 ++ Modules/_testcapimodule.c | 7 +++++++ Python/ceval.c | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py index f3d16e4a2fc92a..080b3e65332af4 100644 --- a/Lib/test/test_capi/test_misc.py +++ b/Lib/test/test_capi/test_misc.py @@ -1180,6 +1180,19 @@ def genf(): yield gen = genf() self.assertEqual(_testcapi.gen_get_code(gen), gen.gi_code) + def test_pyeval_getlocals(self): + # Test PyEval_GetLocals() + x = 1 + self.assertEqual(_testcapi.pyeval_getlocals(), + {'self': self, + 'x': 1}) + + y = 2 + self.assertEqual(_testcapi.pyeval_getlocals(), + {'self': self, + 'x': 1, + 'y': 2}) + @requires_limited_api class TestHeapTypeRelative(unittest.TestCase): diff --git a/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst b/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst new file mode 100644 index 00000000000000..a128d6aef34dfc --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2024-08-06-14-23-11.gh-issue-122728.l-fQ-v.rst @@ -0,0 +1,2 @@ +Fix :c:func:`PyEval_GetLocals` to avoid :exc:`SystemError` ("bad argument to +internal function"). Patch by Victor Stinner. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 1fa7c378412a55..01b6bd89d1371e 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3332,6 +3332,12 @@ test_critical_sections(PyObject *module, PyObject *Py_UNUSED(args)) Py_RETURN_NONE; } +static PyObject * +pyeval_getlocals(PyObject *module, PyObject *Py_UNUSED(args)) +{ + return Py_XNewRef(PyEval_GetLocals()); +} + static PyMethodDef TestMethods[] = { {"set_errno", set_errno, METH_VARARGS}, {"test_config", test_config, METH_NOARGS}, @@ -3476,6 +3482,7 @@ static PyMethodDef TestMethods[] = { {"test_weakref_capi", test_weakref_capi, METH_NOARGS}, {"function_set_warning", function_set_warning, METH_NOARGS}, {"test_critical_sections", test_critical_sections, METH_NOARGS}, + {"pyeval_getlocals", pyeval_getlocals, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Python/ceval.c b/Python/ceval.c index 866328e85bff6d..351ddd2666caf6 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2482,7 +2482,7 @@ PyEval_GetLocals(void) PyFrameObject *f = _PyFrame_GetFrameObject(current_frame); PyObject *ret = f->f_locals_cache; if (ret == NULL) { - PyObject *ret = PyDict_New(); + ret = PyDict_New(); if (ret == NULL) { Py_DECREF(locals); return NULL;