summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-07-18 15:38:28 (GMT)
committerGitHub <noreply@github.com>2024-07-18 15:38:28 (GMT)
commit233ed46e6d2ba1d1f7d83a72ccf9aad9e628ede1 (patch)
tree01bc7b31b77979643876d79795899b740f155a6d /Python/ceval.c
parent98e7d447121f1637c76071548b019ba20a8b8a7a (diff)
downloadcpython-233ed46e6d2ba1d1f7d83a72ccf9aad9e628ede1.zip
cpython-233ed46e6d2ba1d1f7d83a72ccf9aad9e628ede1.tar.gz
cpython-233ed46e6d2ba1d1f7d83a72ccf9aad9e628ede1.tar.bz2
[3.13] gh-118934: Make PyEval_GetLocals return borrowed reference (GH-119769) (#121869)
gh-118934: Make PyEval_GetLocals return borrowed reference (GH-119769) (cherry picked from commit e65cb4c6f01a687f451ad9db1600525e1c5832c4) Co-authored-by: Tian Gao <gaogaotiantian@hotmail.com> Co-authored-by: Alyssa Coghlan <ncoghlan@gmail.com>
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index e2521a4..bbd8a24 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2466,6 +2466,7 @@ _PyEval_GetBuiltinId(_Py_Identifier *name)
PyObject *
PyEval_GetLocals(void)
{
+ // We need to return a borrowed reference here, so some tricks are needed
PyThreadState *tstate = _PyThreadState_GET();
_PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
if (current_frame == NULL) {
@@ -2473,7 +2474,37 @@ PyEval_GetLocals(void)
return NULL;
}
- PyObject *locals = _PyEval_GetFrameLocals();
+ // Be aware that this returns a new reference
+ PyObject *locals = _PyFrame_GetLocals(current_frame);
+
+ if (locals == NULL) {
+ return NULL;
+ }
+
+ if (PyFrameLocalsProxy_Check(locals)) {
+ PyFrameObject *f = _PyFrame_GetFrameObject(current_frame);
+ PyObject *ret = f->f_locals_cache;
+ if (ret == NULL) {
+ PyObject *ret = PyDict_New();
+ if (ret == NULL) {
+ Py_DECREF(locals);
+ return NULL;
+ }
+ f->f_locals_cache = ret;
+ }
+ if (PyDict_Update(ret, locals) < 0) {
+ // At this point, if the cache dict is broken, it will stay broken, as
+ // trying to clean it up or replace it will just cause other problems
+ ret = NULL;
+ }
+ Py_DECREF(locals);
+ return ret;
+ }
+
+ assert(PyMapping_Check(locals));
+ assert(Py_REFCNT(locals) > 1);
+ Py_DECREF(locals);
+
return locals;
}