@@ -53,22 +53,27 @@ static int
53
53
framelocalsproxy_getkeyindex (PyFrameObject * frame , PyObject * key , bool read )
54
54
{
55
55
/*
56
- * Returns the fast locals index of the key
56
+ * Returns -2 (!) if an error occurred; exception will be set.
57
+ * Returns the fast locals index of the key on success:
57
58
* - if read == true, returns the index if the value is not NULL
58
59
* - if read == false, returns the index if the value is not hidden
60
+ * Otherwise returns -1.
59
61
*/
60
62
61
- assert (PyUnicode_CheckExact (key ));
62
-
63
63
PyCodeObject * co = _PyFrame_GetCode (frame -> f_frame );
64
- int found_key = false;
64
+
65
+ // Ensure that the key is hashable.
66
+ Py_hash_t key_hash = PyObject_Hash (key );
67
+ if (key_hash == -1 ) {
68
+ return -2 ;
69
+ }
70
+ bool found = false;
65
71
66
72
// We do 2 loops here because it's highly possible the key is interned
67
73
// and we can do a pointer comparison.
68
74
for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
69
75
PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
70
76
if (name == key ) {
71
- found_key = true;
72
77
if (read ) {
73
78
if (framelocalsproxy_getval (frame -> f_frame , co , i ) != NULL ) {
74
79
return i ;
@@ -78,23 +83,35 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read)
78
83
return i ;
79
84
}
80
85
}
86
+ found = true;
81
87
}
82
88
}
83
-
84
- if (!found_key ) {
85
- // This is unlikely, but we need to make sure. This means the key
86
- // is not interned.
87
- for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
88
- PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
89
- if (_PyUnicode_EQ (name , key )) {
90
- if (read ) {
91
- if (framelocalsproxy_getval (frame -> f_frame , co , i ) != NULL ) {
92
- return i ;
93
- }
94
- } else {
95
- if (!(_PyLocals_GetKind (co -> co_localspluskinds , i ) & CO_FAST_HIDDEN )) {
96
- return i ;
97
- }
89
+ if (found ) {
90
+ // This is an attempt to read an unset local variable or
91
+ // write to a variable that is hidden from regular write operations
92
+ return -1 ;
93
+ }
94
+ // This is unlikely, but we need to make sure. This means the key
95
+ // is not interned.
96
+ for (int i = 0 ; i < co -> co_nlocalsplus ; i ++ ) {
97
+ PyObject * name = PyTuple_GET_ITEM (co -> co_localsplusnames , i );
98
+ Py_hash_t name_hash = PyObject_Hash (name );
99
+ assert (name_hash != -1 ); // keys are exact unicode
100
+ if (name_hash != key_hash ) {
101
+ continue ;
102
+ }
103
+ int same = PyObject_RichCompareBool (name , key , Py_EQ );
104
+ if (same < 0 ) {
105
+ return -2 ;
106
+ }
107
+ if (same ) {
108
+ if (read ) {
109
+ if (framelocalsproxy_getval (frame -> f_frame , co , i ) != NULL ) {
110
+ return i ;
111
+ }
112
+ } else {
113
+ if (!(_PyLocals_GetKind (co -> co_localspluskinds , i ) & CO_FAST_HIDDEN )) {
114
+ return i ;
98
115
}
99
116
}
100
117
}
@@ -109,13 +126,14 @@ framelocalsproxy_getitem(PyObject *self, PyObject *key)
109
126
PyFrameObject * frame = ((PyFrameLocalsProxyObject * )self )-> frame ;
110
127
PyCodeObject * co = _PyFrame_GetCode (frame -> f_frame );
111
128
112
- if (PyUnicode_CheckExact (key )) {
113
- int i = framelocalsproxy_getkeyindex (frame , key , true);
114
- if (i >= 0 ) {
115
- PyObject * value = framelocalsproxy_getval (frame -> f_frame , co , i );
116
- assert (value != NULL );
117
- return Py_NewRef (value );
118
- }
129
+ int i = framelocalsproxy_getkeyindex (frame , key , true);
130
+ if (i == -2 ) {
131
+ return NULL ;
132
+ }
133
+ if (i >= 0 ) {
134
+ PyObject * value = framelocalsproxy_getval (frame -> f_frame , co , i );
135
+ assert (value != NULL );
136
+ return Py_NewRef (value );
119
137
}
120
138
121
139
// Okay not in the fast locals, try extra locals
@@ -145,37 +163,38 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
145
163
return -1 ;
146
164
}
147
165
148
- if (PyUnicode_CheckExact (key )) {
149
- int i = framelocalsproxy_getkeyindex (frame , key , false);
150
- if (i >= 0 ) {
151
- _Py_Executors_InvalidateDependency (PyInterpreterState_Get (), co , 1 );
152
-
153
- _PyLocals_Kind kind = _PyLocals_GetKind (co -> co_localspluskinds , i );
154
- _PyStackRef oldvalue = fast [i ];
155
- PyObject * cell = NULL ;
156
- if (kind == CO_FAST_FREE ) {
157
- // The cell was set when the frame was created from
158
- // the function's closure.
159
- assert (oldvalue .bits != 0 && PyCell_Check (PyStackRef_AsPyObjectBorrow (oldvalue )));
160
- cell = PyStackRef_AsPyObjectBorrow (oldvalue );
161
- } else if (kind & CO_FAST_CELL && oldvalue .bits != 0 ) {
162
- PyObject * as_obj = PyStackRef_AsPyObjectBorrow (oldvalue );
163
- if (PyCell_Check (as_obj )) {
164
- cell = as_obj ;
165
- }
166
+ int i = framelocalsproxy_getkeyindex (frame , key , false);
167
+ if (i == -2 ) {
168
+ return -1 ;
169
+ }
170
+ if (i >= 0 ) {
171
+ _Py_Executors_InvalidateDependency (PyInterpreterState_Get (), co , 1 );
172
+
173
+ _PyLocals_Kind kind = _PyLocals_GetKind (co -> co_localspluskinds , i );
174
+ _PyStackRef oldvalue = fast [i ];
175
+ PyObject * cell = NULL ;
176
+ if (kind == CO_FAST_FREE ) {
177
+ // The cell was set when the frame was created from
178
+ // the function's closure.
179
+ assert (oldvalue .bits != 0 && PyCell_Check (PyStackRef_AsPyObjectBorrow (oldvalue )));
180
+ cell = PyStackRef_AsPyObjectBorrow (oldvalue );
181
+ } else if (kind & CO_FAST_CELL && oldvalue .bits != 0 ) {
182
+ PyObject * as_obj = PyStackRef_AsPyObjectBorrow (oldvalue );
183
+ if (PyCell_Check (as_obj )) {
184
+ cell = as_obj ;
166
185
}
167
- if (cell != NULL ) {
168
- PyObject * oldvalue_o = PyCell_GET (cell );
169
- if (value != oldvalue_o ) {
170
- PyCell_SET (cell , Py_XNewRef (value ));
171
- Py_XDECREF (oldvalue_o );
172
- }
173
- } else if (value != PyStackRef_AsPyObjectBorrow (oldvalue )) {
174
- PyStackRef_XCLOSE (fast [i ]);
175
- fast [i ] = PyStackRef_FromPyObjectNew (value );
186
+ }
187
+ if (cell != NULL ) {
188
+ PyObject * oldvalue_o = PyCell_GET (cell );
189
+ if (value != oldvalue_o ) {
190
+ PyCell_SET (cell , Py_XNewRef (value ));
191
+ Py_XDECREF (oldvalue_o );
176
192
}
177
- return 0 ;
193
+ } else if (value != PyStackRef_AsPyObjectBorrow (oldvalue )) {
194
+ PyStackRef_XCLOSE (fast [i ]);
195
+ fast [i ] = PyStackRef_FromPyObjectNew (value );
178
196
}
197
+ return 0 ;
179
198
}
180
199
181
200
// Okay not in the fast locals, try extra locals
@@ -545,11 +564,12 @@ framelocalsproxy_contains(PyObject *self, PyObject *key)
545
564
{
546
565
PyFrameObject * frame = ((PyFrameLocalsProxyObject * )self )-> frame ;
547
566
548
- if (PyUnicode_CheckExact (key )) {
549
- int i = framelocalsproxy_getkeyindex (frame , key , true);
550
- if (i >= 0 ) {
551
- return 1 ;
552
- }
567
+ int i = framelocalsproxy_getkeyindex (frame , key , true);
568
+ if (i == -2 ) {
569
+ return -1 ;
570
+ }
571
+ if (i >= 0 ) {
572
+ return 1 ;
553
573
}
554
574
555
575
PyObject * extra = ((PyFrameObject * )frame )-> f_extra_locals ;
0 commit comments