2828#define OFF (x ) offsetof(PyFrameObject, x)
2929
3030
31- // Returns borrowed reference or NULL
31+ // Returns new reference or NULL
3232static PyObject *
3333framelocalsproxy_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+
7084static 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 *
142177framelocalsproxy_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