From c540b4043d75a3a85bfec422ccf69b07545e0fe5 Mon Sep 17 00:00:00 2001 From: Jason Fried Date: Thu, 21 Mar 2019 15:54:11 -0700 Subject: [PATCH 1/3] Add some safety around _mysql__fetch_row Users of gc.get_referrers() could cause a SystemError to be raised if this function is running in a different python thread. --- MySQLdb/_mysql.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MySQLdb/_mysql.c b/MySQLdb/_mysql.c index 3c846274..e75a8d31 100644 --- a/MySQLdb/_mysql.c +++ b/MySQLdb/_mysql.c @@ -1284,9 +1284,13 @@ _mysql__fetch_row( if (!self->use) row = mysql_fetch_row(self->result); else { + // This is to prevent gc.get_referrers shenanigans from causing + // the _PyTuple_Resize below from raising a SystemError + PyObject_GC_UnTrack(*r); Py_BEGIN_ALLOW_THREADS; row = mysql_fetch_row(self->result); Py_END_ALLOW_THREADS; + PyObject_GC_Track(*r); } if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) { _mysql_Exception((_mysql_ConnectionObject *)self->conn); From b5fd775881152fa28c758264d51fb57a77f08ace Mon Sep 17 00:00:00 2001 From: Jason Fried Date: Mon, 25 Mar 2019 11:54:38 -0700 Subject: [PATCH 2/3] expand the commend about the gc module --- MySQLdb/_mysql.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MySQLdb/_mysql.c b/MySQLdb/_mysql.c index e75a8d31..80ec7560 100644 --- a/MySQLdb/_mysql.c +++ b/MySQLdb/_mysql.c @@ -1284,8 +1284,10 @@ _mysql__fetch_row( if (!self->use) row = mysql_fetch_row(self->result); else { - // This is to prevent gc.get_referrers shenanigans from causing - // the _PyTuple_Resize below from raising a SystemError + // see: https://docs.python.org/3/library/gc.html#gc.get_referrers + // This function can get a reference to the tuple r, and if that + // code is preempted while holding a ref to r, the _PyTuple_Resize + // will raise a SystemError because the ref count is 2. PyObject_GC_UnTrack(*r); Py_BEGIN_ALLOW_THREADS; row = mysql_fetch_row(self->result); From 1ec1aa7c191435ee2e2395c337eb6602b33f626c Mon Sep 17 00:00:00 2001 From: Inada Naoki Date: Wed, 5 Feb 2020 20:07:40 +0900 Subject: [PATCH 3/3] Update _mysql.c --- MySQLdb/_mysql.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/MySQLdb/_mysql.c b/MySQLdb/_mysql.c index 80ec7560..7811d3ba 100644 --- a/MySQLdb/_mysql.c +++ b/MySQLdb/_mysql.c @@ -1284,15 +1284,9 @@ _mysql__fetch_row( if (!self->use) row = mysql_fetch_row(self->result); else { - // see: https://docs.python.org/3/library/gc.html#gc.get_referrers - // This function can get a reference to the tuple r, and if that - // code is preempted while holding a ref to r, the _PyTuple_Resize - // will raise a SystemError because the ref count is 2. - PyObject_GC_UnTrack(*r); Py_BEGIN_ALLOW_THREADS; row = mysql_fetch_row(self->result); Py_END_ALLOW_THREADS; - PyObject_GC_Track(*r); } if (!row && mysql_errno(&(((_mysql_ConnectionObject *)(self->conn))->connection))) { _mysql_Exception((_mysql_ConnectionObject *)self->conn); @@ -1349,9 +1343,15 @@ _mysql_ResultObject_fetch_row( convert_row = row_converters[how]; if (maxrows) { if (!(r = PyTuple_New(maxrows))) goto error; - rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows, - convert_row); + + // see: https://docs.python.org/3/library/gc.html#gc.get_referrers + // This function can get a reference to the tuple r, and if that + // code is preempted while holding a ref to r, the _PyTuple_Resize + // will raise a SystemError because the ref count is 2. + PyObject_GC_UnTrack(r); + rowsadded = _mysql__fetch_row(self, &r, skiprows, maxrows, convert_row); if (rowsadded == -1) goto error; + PyObject_GC_Track(r); } else { if (self->use) { maxrows = 1000;