From 9e38553132bf7c6fc13e9f268a54ac6533e6ad41 Mon Sep 17 00:00:00 2001 From: Ken Jin Date: Sun, 4 Dec 2022 14:41:23 +0800 Subject: [3.11] gh-99886: Fix crash when freeing objects with managed dictionaries (#99902) Co-authored-by: Erlend E. Aasland --- Lib/test/test_sqlite3/test_regression.py | 12 ++++++++++++ .../2022-11-30-15-29-08.gh-issue-99886.feJkSv.rst | 1 + Objects/dictobject.c | 8 +++++--- 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-30-15-29-08.gh-issue-99886.feJkSv.rst diff --git a/Lib/test/test_sqlite3/test_regression.py b/Lib/test/test_sqlite3/test_regression.py index 0b727ce..9a07e02 100644 --- a/Lib/test/test_sqlite3/test_regression.py +++ b/Lib/test/test_sqlite3/test_regression.py @@ -469,6 +469,18 @@ class RegressionTests(unittest.TestCase): con.executescript("select step(t) from t") self.assertEqual(steps, values) + def test_custom_cursor_object_crash_gh_99886(self): + # This test segfaults on GH-99886 + class MyCursor(sqlite.Cursor): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # this can go before or after the super call; doesn't matter + self.some_attr = None + + with memory_database() as con: + cur = con.cursor(MyCursor) + cur.close() + del cur class RecursiveUseOfCursors(unittest.TestCase): # GH-80254: sqlite3 should not segfault for recursive use of cursors. diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-30-15-29-08.gh-issue-99886.feJkSv.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-30-15-29-08.gh-issue-99886.feJkSv.rst new file mode 100644 index 0000000..8bdaa94 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-30-15-29-08.gh-issue-99886.feJkSv.rst @@ -0,0 +1 @@ +Fix a crash when an object which does not have a dictionary frees its instance values. diff --git a/Objects/dictobject.c b/Objects/dictobject.c index ebbd22e..4a214f8 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -5573,14 +5573,16 @@ _PyObject_FreeInstanceAttributes(PyObject *self) PyTypeObject *tp = Py_TYPE(self); assert(Py_TYPE(self)->tp_flags & Py_TPFLAGS_MANAGED_DICT); PyDictValues **values_ptr = _PyObject_ValuesPointer(self); - if (*values_ptr == NULL) { + PyDictValues *values = *values_ptr; + if (values == NULL) { return; } + *values_ptr = NULL; PyDictKeysObject *keys = CACHED_KEYS(tp); for (Py_ssize_t i = 0; i < keys->dk_nentries; i++) { - Py_XDECREF((*values_ptr)->values[i]); + Py_XDECREF(values->values[i]); } - free_values(*values_ptr); + free_values(values); } PyObject * -- cgit v0.12