Skip to main content

Data Race Detector for Free-Threading Python

Project description

threadcheck

Python License PyPI Tests

中文文档

Python data race detector for the free-threading (no-GIL) era. Detects concurrent access to shared mutable state in multi-threaded Python programs through static analysis and runtime instrumentation.


Problem

Python 3.14 (2026) introduces free-threading, removing the Global Interpreter Lock (GIL). This enables true parallel execution of multi-threaded code, but the ecosystem lacks debugging tools for concurrency bugs. Go has -race, C++ has ThreadSanitizer, Java has SpotBugs. Python has nothing comparable without recompiling the interpreter with Clang and TSan.

threadcheck is a pure-Python race detector that installs with pip and works out of the box.


Features

  • Static analysis -- scans AST for shared mutable state (global, nonlocal, class attributes) and missing lock protection
  • Runtime detection -- instruments code via AST transformation at import time; tracks memory accesses with vector clocks and detects happens-before violations
  • Lock-aware suppression -- understands threading.Lock, threading.RLock, and with-based synchronization; raises confidence when locks are missing and suppresses warnings when they are present
  • Confidence scoring -- each warning tagged HIGH / MEDIUM / LOW based on thread context and lock coverage
  • CLI tool -- single-command static scan or instrumented execution
  • JSON and SARIF output -- suitable for CI/CD pipeline integration

Installation

pip install threadcheck

Requires Python 3.12+. Python 3.14+ is recommended for free-threading features.


Quick Start

Static Analysis

Scan a file or directory for potential race conditions without running any code:

threadcheck scan my_project/

Output:

[WARNING] [HIGH] [unsafe_global] my_project/counter.py:8:8
       Global variable `counter` modified without lock in thread
       Suggestion: use `threading.Lock()` to protect access

JSON output:

threadcheck scan my_project/ --json -o report.json

Runtime Detection

Execute a script with instrumentation to detect actual data races:

threadcheck run my_script.py

Output for a racing script:

Data races detected:
  [!] `counter`
      Thread-28928 (write) at my_script.py:8
      Thread-9888 (write) at my_script.py:8

A script protected with locks reports:

No data races detected

CI Integration

pip install threadcheck
threadcheck scan src/ --json -o threadcheck_report.json

Commands

Command Description Status
scan <path> Static race analysis of file or directory Stable
run <script> Execute script with runtime race detection Beta
check-compat <path> Free-threading compatibility check Planned

Library Usage

from threadcheck import analyze_file, analyze_path

warnings = analyze_file("my_module.py")
warnings = analyze_path("src/")

for w in warnings:
    print(f"{w.file}:{w.line} [{w.confidence.value}] {w.message}")
from threadcheck.dynamic.tracker import ThreadCheckTracker
from threadcheck.dynamic.transform import transform_and_compile

code = transform_and_compile(source, "script.py")
ThreadCheckTracker.start()
exec(code, {"_threadcheck_tracker": ThreadCheckTracker})
ThreadCheckTracker.stop()

print(ThreadCheckTracker.format_races())
ThreadCheckTracker.reset()

Architecture

Static Analysis Pipeline

  1. Parse source into AST
  2. Identify shared mutable state: globals, nonlocals, class attributes (self.x), module-level mutable objects
  3. Detect thread creation sites (threading.Thread)
  4. Cross-reference with lock usage (with lock:, lock.acquire())
  5. Assign confidence: HIGH (thread target, no lock), MEDIUM (thread present, no lock), LOW (suspicious pattern, no thread context)
  6. Report findings with repair suggestions

Runtime Detection Pipeline

  1. Parse source into AST
  2. Identify shared variables per function scope
  3. Transform AST: inject write_before(), lock_acquire(), lock_release() calls around shared variable accesses
  4. Compile and execute transformed code under a tracker that maintains per-thread vector clocks
  5. On lock acquire, synchronize clocks (happens-before merge)
  6. After execution, scan access log for conflicting operations (concurrent writes or write-read pairs with no happens-before relationship)
  7. Report detected races with thread IDs and source locations

Project Structure

threadcheck/
├── pyproject.toml
├── src/
│   └── threadcheck/
│       ├── __init__.py
│       ├── __main__.py
│       ├── _version.py          # single version source
│       ├── cli.py               # argument parsing + dispatch
│       ├── static/
│       │   ├── analyzer.py      # static analysis entry point
│       │   ├── visitors.py      # AST visitors (global, nonlocal, class attr, shared mutable)
│       │   ├── lock_tracker.py  # lock usage analysis
│       │   └── models.py        # RaceWarning, Severity, Confidence models
│       ├── dynamic/
│       │   ├── __main__.py      # run_script entry point
│       │   ├── transform.py     # AST transformation engine
│       │   ├── tracker.py       # runtime tracker with vector clocks
│       │   ├── clock.py         # vector clock implementation
│       │   └── hook.py          # sys.meta_path import hook
│       ├── reporting/
│       │   ├── formatter.py     # terminal output formatting
│       │   └── types.py         # type re-exports
│       └── pytest_plugin.py     # pytest integration (planned)
├── tests/
│   ├── fixtures/                # sample code with known races
│   ├── test_static_analyzer.py
│   └── test_dynamic_detector.py
└── README.md / README_CN.md

Roadmap

Phase Feature Status
1 CLI, static analysis (globals/nonlocals) Done
2 Class attributes, lock suppression, confidence scoring Done
3 AST import hook, runtime instrumentation, vector clocks Done
4 Race report deduplication, enhanced happens-before analysis Planned
5 SARIF output, JSON reporting Planned
6 pytest plugin Planned
7 Free-threading compatibility checker Planned

Limitations

  • Static analysis may produce false positives (reports race that cannot occur at runtime) and false negatives (misses races that involve indirect sharing through aliases or containers)
  • Runtime detection modifies the AST before execution; code that introspects its own source or frame objects may behave differently
  • Runtime instrumentation incurs overhead (approximately 2-5x slowdown for typical code)
  • Lock tracking supports threading.Lock, threading.RLock, and standard with-based patterns; other synchronization primitives (threading.Event, threading.Condition, third-party libraries) are not tracked

License

MIT


Contributing

Contributions are welcome. Please open an issue or submit a pull request on GitHub.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

threadcheck-0.0.1.1.tar.gz (34.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

threadcheck-0.0.1.1-py3-none-win_amd64.whl (26.1 kB view details)

Uploaded Python 3Windows x86-64

threadcheck-0.0.1.1-py3-none-manylinux_2_28_x86_64.whl (26.0 kB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

threadcheck-0.0.1.1-py3-none-macosx_11_0_arm64.whl (26.0 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file threadcheck-0.0.1.1.tar.gz.

File metadata

  • Download URL: threadcheck-0.0.1.1.tar.gz
  • Upload date:
  • Size: 34.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for threadcheck-0.0.1.1.tar.gz
Algorithm Hash digest
SHA256 514fe0f139e90eecd01a6fa8d8ca7faa7139aecd3c8b95746cd2a50ff40329a4
MD5 d2189d2d22661e30d7592d15ea2f8ad9
BLAKE2b-256 cb527987df92508f0686314dfe949d877cb5e263235486eea7e28623a50a1273

See more details on using hashes here.

Provenance

The following attestation bundles were made for threadcheck-0.0.1.1.tar.gz:

Publisher: release.yml on ChidcGithub/Threadcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file threadcheck-0.0.1.1-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for threadcheck-0.0.1.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 1c7560e0bebb2eb79eda0adb5a65df9cff27cb453720570c2d8f45190ca1defd
MD5 ceee193f8a9afca6fee666c138b98d50
BLAKE2b-256 6ac60707a79079582740562bafa709940d98b6e54bf3504fde9aaebd8f748fb2

See more details on using hashes here.

Provenance

The following attestation bundles were made for threadcheck-0.0.1.1-py3-none-win_amd64.whl:

Publisher: release.yml on ChidcGithub/Threadcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file threadcheck-0.0.1.1-py3-none-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for threadcheck-0.0.1.1-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8d455f37f53fc065abdc224763b531be5febe954567ca56d825f4a87d4706ca1
MD5 02ac6f178786329c3846ea319460e804
BLAKE2b-256 21cc2c0a81fed2918549750fa6e703bd2d4f2b329206e03ee0dc8f44d8e89f08

See more details on using hashes here.

Provenance

The following attestation bundles were made for threadcheck-0.0.1.1-py3-none-manylinux_2_28_x86_64.whl:

Publisher: release.yml on ChidcGithub/Threadcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file threadcheck-0.0.1.1-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for threadcheck-0.0.1.1-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 567a339d3de0dc6d67a1a13b8ecc968abe9c1ad7542fed1a4377f5164c487658
MD5 2078c3d6c676132d449f708b268995ab
BLAKE2b-256 37072c47d4037d86ea06b545015f5797b8babd61166aa65a136058dd72ea93c9

See more details on using hashes here.

Provenance

The following attestation bundles were made for threadcheck-0.0.1.1-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on ChidcGithub/Threadcheck

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page