Issue 31770: crash and refleaks when calling sqlite3.Cursor.init() more than once (original) (raw)

The following code crashes: import sqlite3 import weakref def callback(*args): pass

connection = sqlite3.connect(":memory:") cursor = sqlite3.Cursor(connection) ref = weakref.ref(cursor, callback) cursor.init(connection) del cursor del ref

IIUC, this is because pysqlite_cursor_init() (in Modules/_sqlite/cursor.c) sets self->in_weakreflist to NULL, and thus corrupts the weakref list. Later, clear_weakref() (in Objects/weakrefobject.c) tries to remove a reference from the corrupted list, and crashes.

In every other place (that i saw) where such a weakreflist field is used, it is set to NULL right after allocating the object (usually in new()), or just not set at all, e.g. in functools.partial. So since PyType_GenericNew() is the new() of sqlite3.Cursor, ISTM that the simplest solution is to not touch self->in_weakreflist at all in pysqlite_cursor_init().

Also, the following code results in refleaks: import sys import sqlite3 connection = sqlite3.connect(":memory:") cursor = sqlite3.Cursor(connection) refcount_before = sys.gettotalrefcount() cursor.init(connection) print(sys.gettotalrefcount() - refcount_before) # should be close to 0

This is because pysqlite_cursor_init() doesn't decref before assigning to fields of self.

I would open a PR to fix this soon.