python / python/cpython

sqlite3 Connection and Cursor segfault if __init__ is bypassed (by subclass or __new__ call)

オープン
#152,954 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

extension-modules topic-sqlite3 type-crash
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

Crash report

What happened?
import sqlite3
con = sqlite3.Connection.__new__(sqlite3.Connection)
print(con.row_factory)

or, more likely:

import sqlite3
class MyCon(sqlite3.Connection):
  def __init__(self, *a, **kw):
    if self.row_factory:
      pass
    super().__init__()
c = MyCon(':memory:')

Both give:

fish: Job 1, './python.exe repro.py' terminated by signal SIGSEGV (Address boundary error)

LLDB:

Process 76976 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
       frame #0: 0x0000000100a93df0 _sqlite3.cpython-316d-darwin.so`Py_INCREF(op=0x0000000000000000) at refcount.h:286:31 [opt] [inlined]
   283 	        _Py_atomic_add_ssize(&op->ob_ref_shared, (1 << _Py_REF_SHARED_SHIFT));
   284 	    }
   285 	#elif SIZEOF_VOID_P > 4
-> 286 	    uint32_t cur_refcnt = op->ob_refcnt;
   287 	    if (cur_refcnt >= _Py_IMMORTAL_INITIAL_REFCNT) {
   288 	        // the object is immortal
   289 	        _Py_INCREF_IMMORTAL_STAT_INC();
Target 0: (python.exe) stopped.
warning: _sqlite3.cpython-316d-darwin.so was compiled with optimization - stepping may behave oddly; variables may not be available.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x0)
   * frame #0: 0x0000000100a93df0 _sqlite3.cpython-316d-darwin.so`Py_INCREF(op=0x0000000000000000) at refcount.h:286:31 [opt] [inlined]
     frame #1: 0x0000000100a93df0 _sqlite3.cpython-316d-darwin.so`_Py_NewRef(obj=0x0000000000000000) at refcount.h:536:5 [opt] [inlined]
     frame #2: 0x0000000100a93df0 _sqlite3.cpython-316d-darwin.so`connection_get_row_factory(op=0x0000007a371d4040, closure=0x0000000000000000) at connection.c:564:12 [opt]

So, basically, until the tp_init is called, both row_factory and text_factory are NULL, but are treated as always being python objects, causing a number of segfaults.

This was discovered when fixing: gh-152817 / gh-152818 which was a follow-on from: gh-149738 / gh-149754

I think the fix here is to add a tp_new that initializes the fields before python has a chance to mess with the object, and then rely on the associated guards that prevent delattr on those fields (in the above PRs)

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.16.0a0 (heads/main-dirty:c4739533f33, Jul 3 2026, 12:34:46) [Clang 21.0.0 (clang-2100.3.20.102)]

Linked PRs
  • gh-152956

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

connection.c の sqlite3 接続実装、特に connection_get_row_factory から始め、tp_init 前のアクセスを示す reproducer を確認してください。リンクされている PR gh-152956 を確認し、報告されている new と subclass の例を実行してください。これらのケースで segfault が発生しなくなり、関連する sqlite3 テストでカバーされれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
c, python
領域
databases
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
停滞
明瞭さ
明確に書かれている
初心者へのやさしさ
25/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。