Skip to content

gh-160699: Prevent concurrent reuse of cached SQLite statements - #160706

Open
mangod12 wants to merge 4 commits into
python:mainfrom
mangod12:issue-160699-sqlite-threading
Open

mangod12 wants to merge 4 commits into
python:mainfrom
mangod12:issue-160699-sqlite-threading

Conversation

@mangod12

Copy link
Copy Markdown

Summary

Concurrent calls to execute() on a shared SQLite connection can obtain the same cached sqlite3_stmt before SQLite marks it busy. The cursor releases the GIL around SQLite operations, leaving a race where concurrent cursors can reset or use the same statement and crash the process.

Reserve cached statements before releasing the GIL. If a cached statement is already reserved, create an uncached statement for the concurrent execution. Release the reservation when the statement is reset.

Add a regression test that runs concurrent parameterized queries on a shared connection and verifies the returned BLOB contents.

Fixes gh-160699.

Verification

  • Windows debug build succeeded.
  • PCbuild/amd64/python_d.exe -m unittest test.test_sqlite3.test_dbapi: 211 passed, 2 skipped.
  • Tools/patchcheck/patchcheck.py: passed; NEWS fragment recognized.

@python-cla-bot

python-cla-bot Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app

bedevere-app Bot commented Oct 26, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@mangod12

Copy link
Copy Markdown
Author

CI for PR #160706 fails on all three macOS jobs in the new test_concurrent_queries_on_shared_connection: it segfaults inside sqlite3_prepare_v2 while threads share the connection. I pushed cf13208 to explicitly request SQLITE_OPEN_FULLMUTEX whenever the linked SQLite build has mutex support, while keeping the statement reservation fix. SQLite documents that flag as selecting serialized mode and notes sqlite3_threadsafe() alone does not report runtime mode: https://sqlite.org/threadsafe.html

The new CI run will tell us whether that addresses the macOS failure. I could not build CPython locally here because the Windows C toolchain is unavailable.

@mangod12

Copy link
Copy Markdown
Author

@erlend-aasland The latest CI run for 76eb2d3 failed on macOS Intel with a hosted-runner communication error; GitHub’s annotation reports that the runner lost communication with the server, and the detailed job log is unavailable. Could you rerun that job when convenient? The other macOS jobs passed.

Copy link
Copy Markdown
Author

@erlend-aasland A separate blocker surfaced in the Read the Docs preview for build 35421294 (commit 76eb2d3): it fetched refs/pull/160706/head, then failed before the docs build with fatal: reference is not a tree when checking out that commit. Could you check the preview’s commit/ref resolution or trigger a fresh preview? The failure appears to happen before Sphinx runs.

@StanFromIreland StanFromIreland added the AI-needs-explanation AI-assisted work that needs further explanation and follow up from the contributor label Oct 28, 2026
@bedevere-app

bedevere-app Bot commented Oct 28, 2026

Copy link
Copy Markdown

Thank you for your interest in contributing to Python. This is a community-driven project, and we want it to be a welcoming place to learn and collaborate.

Contributors are responsible for reviewing and understanding what they submit, checking its claims, and being able to explain changes in their own words. This helps reviewers focus on the contribution and leaves more time to support other contributors.

This contribution appears to have been authored with AI assistance. Please explain your contribution in your own words and describe how you checked its correctness.

Please read our guidelines for using AI tools.

@mangod12

Copy link
Copy Markdown
Author

Yes it was done with help of ai. And thanks for the reply.

The issue as i understood was that concurrent execution calls on a shared connection can pick the same cached SQLite statement before sqlite3 mark it busy. Both threads can then try to use that same statement.

This fix reserves that statement with a flag ( in_use) so other cursor gets an uncached one.
Also used fullmutex so that sql lite processes on the shared connection are in order.

For regression i ran concurrent queries from 4 threads sharing connection and returned blob data were checked also that subprocesses end cleanly.

For testing i had issues initially then i installed c toolchain and ran it with help of ai.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI-needs-explanation AI-assisted work that needs further explanation and follow up from the contributor awaiting review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sqlite3: concurrent execute() on a shared Connection crashes the process with a native access violation (threadsafety == 3)

2 participants