From 2269af5ec1675d1b3b6d915f2213001c818f5918 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 20 Feb 2025 17:07:31 -0500 Subject: [PATCH 1/8] Remove the PyCell_Get usage for framelocalsproxy --- Objects/frameobject.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index dbeee50fcff090..ff30550bc016c1 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -28,7 +28,7 @@ #define OFF(x) offsetof(PyFrameObject, x) -// Returns borrowed reference or NULL +// Returns new reference or NULL static PyObject * framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) { @@ -57,7 +57,9 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) } if (cell != NULL) { - value = PyCell_GET(cell); + value = PyCell_GetRef(cell); + } else { + Py_XINCREF(value); } if (value == NULL) { @@ -67,6 +69,17 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) return value; } +static bool +framelocalsproxy_hasval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) +{ + PyObject *value = framelocalsproxy_getval(frame, co, i); + if (value == NULL) { + return false; + } + Py_DECREF(value); + return true; +} + static int framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) { @@ -93,7 +106,7 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (name == key) { if (read) { - if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) { + if (framelocalsproxy_hasval(frame->f_frame, co, i)) { return i; } } else { @@ -124,7 +137,7 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) } if (same) { if (read) { - if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) { + if (framelocalsproxy_hasval(frame->f_frame, co, i)) { return i; } } else { @@ -151,7 +164,7 @@ framelocalsproxy_getitem(PyObject *self, PyObject *key) if (i >= 0) { PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i); assert(value != NULL); - return Py_NewRef(value); + return value; } // Okay not in the fast locals, try extra locals @@ -297,8 +310,7 @@ framelocalsproxy_keys(PyObject *self, PyObject *Py_UNUSED(ignored)) } for (int i = 0; i < co->co_nlocalsplus; i++) { - PyObject *val = framelocalsproxy_getval(frame->f_frame, co, i); - if (val) { + if (framelocalsproxy_hasval(frame->f_frame, co, i)) { PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (PyList_Append(names, name) < 0) { Py_DECREF(names); @@ -511,8 +523,10 @@ framelocalsproxy_values(PyObject *self, PyObject *Py_UNUSED(ignored)) if (value) { if (PyList_Append(values, value) < 0) { Py_DECREF(values); + Py_DECREF(value); return NULL; } + Py_DECREF(value); } } @@ -550,16 +564,19 @@ framelocalsproxy_items(PyObject *self, PyObject *Py_UNUSED(ignored)) PyObject *pair = PyTuple_Pack(2, name, value); if (pair == NULL) { Py_DECREF(items); + Py_DECREF(value); return NULL; } if (PyList_Append(items, pair) < 0) { Py_DECREF(items); Py_DECREF(pair); + Py_DECREF(value); return NULL; } Py_DECREF(pair); + Py_DECREF(value); } } @@ -601,7 +618,7 @@ framelocalsproxy_length(PyObject *self) } for (int i = 0; i < co->co_nlocalsplus; i++) { - if (framelocalsproxy_getval(frame->f_frame, co, i) != NULL) { + if (framelocalsproxy_hasval(frame->f_frame, co, i)) { size++; } } @@ -2066,9 +2083,7 @@ _PyFrame_HasHiddenLocals(_PyInterpreterFrame *frame) _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); if (kind & CO_FAST_HIDDEN) { - PyObject* value = framelocalsproxy_getval(frame, co, i); - - if (value != NULL) { + if (framelocalsproxy_hasval(frame, co, i)) { return true; } } From 25491daddd3722b8dced3e9d99cb82a8beb2ea92 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 20 Feb 2025 19:08:04 -0500 Subject: [PATCH 2/8] Fix warning --- Objects/frameobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ff30550bc016c1..13cb882a8c089c 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -57,7 +57,7 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) } if (cell != NULL) { - value = PyCell_GetRef(cell); + value = PyCell_GetRef((PyCellObject *)cell); } else { Py_XINCREF(value); } From 2a98b816fa975426d398e308d6a679f36e70f349 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Fri, 21 Feb 2025 11:33:35 -0500 Subject: [PATCH 3/8] Fix style Co-authored-by: Sam Gross --- Objects/frameobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 13cb882a8c089c..d8a550aa55f334 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -58,7 +58,8 @@ framelocalsproxy_getval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) if (cell != NULL) { value = PyCell_GetRef((PyCellObject *)cell); - } else { + } + else { Py_XINCREF(value); } From 2828ee21bb144e8bdc9e57259caf653fc62883cc Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 25 Feb 2025 15:49:51 -0500 Subject: [PATCH 4/8] Do check & read in a single operation --- Objects/frameobject.c | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index d8a550aa55f334..0805f5e944cb13 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -82,7 +82,7 @@ framelocalsproxy_hasval(_PyInterpreterFrame *frame, PyCodeObject *co, int i) } static int -framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) +framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyObject **value_ptr) { /* * Returns -2 (!) if an error occurred; exception will be set. @@ -90,8 +90,14 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) * - if read == true, returns the index if the value is not NULL * - if read == false, returns the index if the value is not hidden * Otherwise returns -1. + * + * If read == true and value_ptr is not NULL, *value_ptr is set to + * the value of the key if it is found (with a new reference). */ + // value_ptr should only be given if we are reading the value + assert(read || value_ptr == NULL); + PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); // Ensure that the key is hashable. @@ -99,6 +105,7 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) if (key_hash == -1) { return -2; } + bool found = false; // We do 2 loops here because it's highly possible the key is interned @@ -107,7 +114,13 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i); if (name == key) { if (read) { - if (framelocalsproxy_hasval(frame->f_frame, co, i)) { + PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i); + if (value != NULL) { + if (value_ptr != NULL) { + *value_ptr = value; + } else { + Py_DECREF(value); + } return i; } } else { @@ -138,7 +151,13 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject* key, bool read) } if (same) { if (read) { - if (framelocalsproxy_hasval(frame->f_frame, co, i)) { + PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i); + if (value != NULL) { + if (value_ptr != NULL) { + *value_ptr = value; + } else { + Py_DECREF(value); + } return i; } } else { @@ -157,22 +176,23 @@ framelocalsproxy_getitem(PyObject *self, PyObject *key) { PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); + PyObject *value = NULL; - int i = framelocalsproxy_getkeyindex(frame, key, true); + int i = framelocalsproxy_getkeyindex(frame, key, true, &value); if (i == -2) { return NULL; } if (i >= 0) { - PyObject *value = framelocalsproxy_getval(frame->f_frame, co, i); assert(value != NULL); return value; } + assert(value == NULL); // Okay not in the fast locals, try extra locals PyObject *extra = frame->f_extra_locals; if (extra != NULL) { - PyObject *value = PyDict_GetItem(extra, key); + value = PyDict_GetItem(extra, key); if (value != NULL) { return Py_NewRef(value); } @@ -190,7 +210,7 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value) _PyStackRef *fast = _PyFrame_GetLocalsArray(frame->f_frame); PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); - int i = framelocalsproxy_getkeyindex(frame, key, false); + int i = framelocalsproxy_getkeyindex(frame, key, false, NULL); if (i == -2) { return -1; } @@ -631,7 +651,7 @@ framelocalsproxy_contains(PyObject *self, PyObject *key) { PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - int i = framelocalsproxy_getkeyindex(frame, key, true); + int i = framelocalsproxy_getkeyindex(frame, key, true, NULL); if (i == -2) { return -1; } @@ -742,7 +762,7 @@ framelocalsproxy_pop(PyObject* self, PyObject *const *args, Py_ssize_t nargs) PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - int i = framelocalsproxy_getkeyindex(frame, key, false); + int i = framelocalsproxy_getkeyindex(frame, key, false, NULL); if (i == -2) { return NULL; } From c22ba6b3b89d6fd92a29976c6f662454d0edb79c Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 25 Feb 2025 15:51:36 -0500 Subject: [PATCH 5/8] C style --- Objects/frameobject.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 0805f5e944cb13..ee032ebdf4a157 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -118,7 +118,8 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyO if (value != NULL) { if (value_ptr != NULL) { *value_ptr = value; - } else { + } + else { Py_DECREF(value); } return i; @@ -155,7 +156,8 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyO if (value != NULL) { if (value_ptr != NULL) { *value_ptr = value; - } else { + } + else { Py_DECREF(value); } return i; From 037360154accf422787f484080fd395002737b63 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 25 Feb 2025 15:57:21 -0500 Subject: [PATCH 6/8] Fix lint --- Objects/frameobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index ee032ebdf4a157..a5c3ea675c6dd7 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -90,7 +90,7 @@ framelocalsproxy_getkeyindex(PyFrameObject *frame, PyObject *key, bool read, PyO * - if read == true, returns the index if the value is not NULL * - if read == false, returns the index if the value is not hidden * Otherwise returns -1. - * + * * If read == true and value_ptr is not NULL, *value_ptr is set to * the value of the key if it is found (with a new reference). */ From e396e1bed0c358ccacccdf73a4f75d104fdea039 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Tue, 25 Feb 2025 15:58:29 -0500 Subject: [PATCH 7/8] Remove unused var --- Objects/frameobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index a5c3ea675c6dd7..c618f2d38bb753 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -177,7 +177,6 @@ static PyObject * framelocalsproxy_getitem(PyObject *self, PyObject *key) { PyFrameObject *frame = PyFrameLocalsProxyObject_CAST(self)->frame; - PyCodeObject *co = _PyFrame_GetCode(frame->f_frame); PyObject *value = NULL; int i = framelocalsproxy_getkeyindex(frame, key, true, &value); From 72776f043d3c78a885984af1d60a7596c2e46c98 Mon Sep 17 00:00:00 2001 From: Tian Gao Date: Thu, 27 Feb 2025 13:38:02 -0500 Subject: [PATCH 8/8] Use PyDict_GetItemRef --- Objects/frameobject.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index c618f2d38bb753..001b58dc052416 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -193,9 +193,11 @@ framelocalsproxy_getitem(PyObject *self, PyObject *key) PyObject *extra = frame->f_extra_locals; if (extra != NULL) { - value = PyDict_GetItem(extra, key); + if (PyDict_GetItemRef(extra, key, &value) < 0) { + return NULL; + } if (value != NULL) { - return Py_NewRef(value); + return value; } }