Skip to content

Commit 6140b08

Browse files
gh-127271: Remove the PyCell_Get usage for framelocalsproxy (#130383)
1 parent 043ab3a commit 6140b08

File tree

1 file changed

+59
-20
lines changed

1 file changed

+59
-20
lines changed

Objects/frameobject.c

+59-20
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#define OFF(x) offsetof(PyFrameObject, x)
2929

3030

31-
// Returns borrowed reference or NULL
31+
// Returns new reference or NULL
3232
static PyObject *
3333
framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
3434
{
@@ -57,7 +57,10 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
5757
}
5858

5959
if (cell != NULL) {
60-
value = PyCell_GET(cell);
60+
value = PyCell_GetRef((PyCellObject *)cell);
61+
}
62+
else {
63+
Py_XINCREF(value);
6164
}
6265

6366
if (value == NULL) {
@@ -67,24 +70,42 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
6770
return value;
6871
}
6972

73+
static bool
74+
framelocalsproxy_hasval(_PyInterpreterFrame *frame, PyCodeObject *co, int i)
75+
{
76+
PyObject *value = framelocalsproxy_getval(frame, co, i);
77+
if (value == NULL) {
78+
return false;
79+
}
80+
Py_DECREF(value);
81+
return true;
82+
}
83+
7084
static int
71-
framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
85+
framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyObject **value_ptr)
7286
{
7387
/*
7488
* Returns -2 (!) if an error occurred; exception will be set.
7589
* Returns the fast locals index of the key on success:
7690
* - if read == true, returns the index if the value is not NULL
7791
* - if read == false, returns the index if the value is not hidden
7892
* Otherwise returns -1.
93+
*
94+
* If read == true and value_ptr is not NULL, *value_ptr is set to
95+
* the value of the key if it is found (with a new reference).
7996
*/
8097

98+
// value_ptr should only be given if we are reading the value
99+
assert(read || value_ptr == NULL);
100+
81101
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
82102

83103
// Ensure that the key is hashable.
84104
Py_hash_t key_hash = PyObject_Hash(key);
85105
if (key_hash == -1) {
86106
return -2;
87107
}
108+
88109
bool found = false;
89110

90111
// We do 2 loops here because it's highly possible the key is interned
@@ -93,7 +114,14 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
93114
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
94115
if (name == key) {
95116
if (read) {
96-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
117+
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
118+
if (value != NULL) {
119+
if (value_ptr != NULL) {
120+
*value_ptr = value;
121+
}
122+
else {
123+
Py_DECREF(value);
124+
}
97125
return i;
98126
}
99127
} else {
@@ -124,7 +152,14 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
124152
}
125153
if (same) {
126154
if (read) {
127-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
155+
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
156+
if (value != NULL) {
157+
if (value_ptr != NULL) {
158+
*value_ptr = value;
159+
}
160+
else {
161+
Py_DECREF(value);
162+
}
128163
return i;
129164
}
130165
} else {
@@ -142,25 +177,27 @@ static PyObject *
142177
framelocalsproxy_getitem(PyObject *self, PyObject *key)
143178
{
144179
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
145-
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
180+
PyObject *value = NULL;
146181

147-
int i = framelocalsproxy_getkeyindex(frame, key, true);
182+
int i = framelocalsproxy_getkeyindex(frame, key, true, &value);
148183
if (i == -2) {
149184
return NULL;
150185
}
151186
if (i >= 0) {
152-
PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i);
153187
assert(value != NULL);
154-
return Py_NewRef(value);
188+
return value;
155189
}
190+
assert(value == NULL);
156191

157192
// Okay not in the fast locals, try extra locals
158193

159194
PyObject *extra = frame->f_extra_locals;
160195
if (extra != NULL) {
161-
PyObject *value = PyDict_GetItem(extra, key);
196+
if (PyDict_GetItemRef(extra, key, &value) < 0) {
197+
return NULL;
198+
}
162199
if (value != NULL) {
163-
return Py_NewRef(value);
200+
return value;
164201
}
165202
}
166203

@@ -176,7 +213,7 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
176213
_PyStackRef *fast = _PyFrame_GetLocalsArray(frame->f_frame);
177214
PyCodeObject *co = _PyFrame_GetCode(frame->f_frame);
178215

179-
int i = framelocalsproxy_getkeyindex(frame, key, false);
216+
int i = framelocalsproxy_getkeyindex(frame, key, false, NULL);
180217
if (i == -2) {
181218
return -1;
182219
}
@@ -297,8 +334,7 @@ framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored))
297334
}
298335

299336
for (int i = 0; i < co->co_nlocalsplus; i++) {
300-
PyObject *val = framelocalsproxy_getval(frame->f_frame, co, i);
301-
if (val) {
337+
if (framelocalsproxy_hasval(frame->f_frame, co, i)) {
302338
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
303339
if (PyList_Append(names, name) < 0) {
304340
Py_DECREF(names);
@@ -511,8 +547,10 @@ framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored))
511547
if (value) {
512548
if (PyList_Append(values, value) < 0) {
513549
Py_DECREF(values);
550+
Py_DECREF(value);
514551
return NULL;
515552
}
553+
Py_DECREF(value);
516554
}
517555
}
518556

@@ -550,16 +588,19 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored))
550588
PyObject *pair = PyTuple_Pack(2, name, value);
551589
if (pair == NULL) {
552590
Py_DECREF(items);
591+
Py_DECREF(value);
553592
return NULL;
554593
}
555594

556595
if (PyList_Append(items, pair) < 0) {
557596
Py_DECREF(items);
558597
Py_DECREF(pair);
598+
Py_DECREF(value);
559599
return NULL;
560600
}
561601

562602
Py_DECREF(pair);
603+
Py_DECREF(value);
563604
}
564605
}
565606

@@ -601,7 +642,7 @@ framelocalsproxy_length(PyObject *self)
601642
}
602643

603644
for (int i = 0; i < co->co_nlocalsplus; i++) {
604-
if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) {
645+
if (framelocalsproxy_hasval(frame->f_frame, co, i)) {
605646
size++;
606647
}
607648
}
@@ -613,7 +654,7 @@ framelocalsproxy_contains(PyObject *self, PyObject *key)
613654
{
614655
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
615656

616-
int i = framelocalsproxy_getkeyindex(frame, key, true);
657+
int i = framelocalsproxy_getkeyindex(frame, key, true, NULL);
617658
if (i == -2) {
618659
return -1;
619660
}
@@ -724,7 +765,7 @@ framelocalsproxy_pop(PyObject* self, PyObject *const *args, Py_ssize_t nargs)
724765

725766
PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame;
726767

727-
int i = framelocalsproxy_getkeyindex(frame, key, false);
768+
int i = framelocalsproxy_getkeyindex(frame, key, false, NULL);
728769
if (i == -2) {
729770
return NULL;
730771
}
@@ -2066,9 +2107,7 @@ _PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame)
20662107
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
20672108

20682109
if (kind & CO_FAST_HIDDEN) {
2069-
PyObject* value = framelocalsproxy_getval(frame, co, i);
2070-
2071-
if (value != NULL) {
2110+
if (framelocalsproxy_hasval(frame, co, i)) {
20722111
return true;
20732112
}
20742113
}

0 commit comments

Comments
 (0)