Skip to content

Commit 1458ea0

Browse files
[3.14] gh-146090: fix memory management of internal sqlite3 callback contexts (GH-146569) (#146595)
gh-146090: fix memory management of internal `sqlite3` callback contexts (GH-146569) (cherry picked from commit aa66807) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent 883b6d2 commit 1458ea0

File tree

4 files changed

+30
-7
lines changed

4 files changed

+30
-7
lines changed

Lib/test/test_sqlite3/test_hooks.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,21 @@ def test_collation_register_twice(self):
120120
self.assertEqual(result[0][0], 'b')
121121
self.assertEqual(result[1][0], 'a')
122122

123+
def test_collation_register_when_busy(self):
124+
# See https://github.com/python/cpython/issues/146090.
125+
con = self.con
126+
con.create_collation("mycoll", lambda x, y: (x > y) - (x < y))
127+
con.execute("CREATE TABLE t(x TEXT)")
128+
con.execute("INSERT INTO t VALUES (?)", ("a",))
129+
con.execute("INSERT INTO t VALUES (?)", ("b",))
130+
con.commit()
131+
132+
cursor = self.con.execute("SELECT x FROM t ORDER BY x COLLATE mycoll")
133+
next(cursor)
134+
# Replace the collation while the statement is active -> SQLITE_BUSY.
135+
with self.assertRaises(sqlite.OperationalError) as cm:
136+
self.con.create_collation("mycoll", lambda a, b: 0)
137+
123138
def test_deregister_collation(self):
124139
"""
125140
Register a collation, then deregister it. Make sure an error is raised if we try
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`sqlite3`: properly raise :exc:`MemoryError` instead of :exc:`SystemError`
2+
when a context callback fails to be allocated. Patch by Bénédikt Tran.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
:mod:`sqlite3`: fix a crash when :meth:`sqlite3.Connection.create_collation`
2+
fails with `SQLITE_BUSY <https://sqlite.org/rescode.html#busy>`__. Patch by
3+
Bénédikt Tran.

Modules/_sqlite/connection.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,13 +1110,16 @@ static callback_context *
11101110
create_callback_context(PyTypeObject *cls, PyObject *callable)
11111111
{
11121112
callback_context *ctx = PyMem_Malloc(sizeof(callback_context));
1113-
if (ctx != NULL) {
1114-
PyObject *module = PyType_GetModule(cls);
1115-
ctx->refcount = 1;
1116-
ctx->callable = Py_NewRef(callable);
1117-
ctx->module = Py_NewRef(module);
1118-
ctx->state = pysqlite_get_state(module);
1113+
if (ctx == NULL) {
1114+
PyErr_NoMemory();
1115+
return NULL;
11191116
}
1117+
1118+
PyObject *module = PyType_GetModule(cls);
1119+
ctx->refcount = 1;
1120+
ctx->callable = Py_NewRef(callable);
1121+
ctx->module = Py_NewRef(module);
1122+
ctx->state = pysqlite_get_state(module);
11201123
return ctx;
11211124
}
11221125

@@ -2250,7 +2253,7 @@ pysqlite_connection_create_collation_impl(pysqlite_Connection *self,
22502253
* the context before returning.
22512254
*/
22522255
if (callable != Py_None) {
2253-
free_callback_context(ctx);
2256+
decref_callback_context(ctx);
22542257
}
22552258
set_error_from_db(self->state, self->db);
22562259
return NULL;

0 commit comments

Comments
 (0)