Skip to content

About

Is a static concurrency analysis tool for C and C++ that helps detect threading and synchronization bugs before runtime. It focuses on shared-state correctness, lock discipline, thread lifecycle validation, and atomic usage analysis to surface race-prone patterns, missing synchronization, and structural concurrency flaws in a CI-friendly way.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

CoreTrace Concurrency Analyzer

Find data races, deadlocks and thread-lifetime bugs in C and C++ before they find you.

A static analyzer that compiles your code to LLVM IR and reasons about threads, locks, fork and signal handlers — no instrumentation, no test run, no flaky reproduction.

cmake-ctest Release License: Apache 2.0 LLVM 20 GitHub Action

Quick start · Rules · CI · How it works · Docs


See it in action

int shared_counter = 0;

void* increment(void* arg) {
    for (int i = 0; i < 10000; i++)
        shared_counter++;              // two threads, no lock
    return NULL;
}

int main(void) {
    pthread_t t1, t2;
    pthread_create(&t1, NULL, increment, NULL);
    pthread_create(&t2, NULL, increment, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
}
$ coretrace_concurrency_analyzer race.c --analyze

Function: increment
	severity: ERROR
	ruleId: DataRaceGlobal
	cwe: CWE-362
	symbol: shared_counter
	[!!!Error] unsynchronized concurrent access to global 'shared_counter'
	     ↳ first access: read at race.c:10:23 in increment (thread entries: increment)
	     ↳ conflicting access: write at race.c:10:23 in increment (thread entries: increment)
	     ↳ possible conflict kinds: read/write, write/write
	     ↳ no common recognized lock protects the conflicting accesses

The same report is available as JSON and SARIF, so it lands directly in GitHub Code Scanning. There, a finding's message is its plain statement and its notes are data (a notes array in JSON, a notes result property in SARIF); the [!!!Error] tag and the ↳ lines lay out the human report only.

Quick start

With Docker — nothing to install but a container runtime:

docker run --rm -v "$PWD:/work" \
  ghcr.io/coretrace/coretrace-concurrency-analyzer:v0.8.0 file.c --analyze

On a whole project — reuse the compilation database your build already produces:

coretrace_concurrency_analyzer --compile-commands=build/compile_commands.json

From source (LLVM/Clang 20, CMake ≥ 3.21) — see Building.

What it catches

Rule --rules= Catches
Data race data-race shared globals accessed concurrently with no common lock
Lock-order deadlock deadlock-lock-order lock-order inversions and self-deadlock
Missing join missing-join pthread / std::thread handles never joined nor detached
Condition wait condition-wait a wait that does not recheck its predicate after waking
Weak publication weak-publication data published through an atomic flag without release/acquire
Thread arg escapes frame thread-arg-escape a thread handed a pointer into its creator's stack
Thread arg freed early thread-arg-freed memory freed before the thread using it is joined
Thread-local escape thread-local-escape a thread-local used after its thread has ended
Fork after threads fork-after-thread fork in a threaded program with no exec in the child
Unreaped child unreaped-child children that are never waited for
Unsafe signal handler unsafe-signal-handler handlers reaching non async-signal-safe calls

All rules run by default. Each one documents what it proves and what it deliberately does not in docs/rules.md.

In CI

permissions:
  contents: read
  security-events: write   # for the Code Scanning upload

steps:
  - uses: actions/checkout@v4
  - uses: CoreTrace/coretrace-concurrency-analyzer@v0
    with:
      compile-commands: build/compile_commands.json
      fail-on: error

The action runs the published image (it starts in seconds), uploads SARIF to Code Scanning, then fails the job if needed. Exit codes separate “found something” (2) from “could not analyze” (1), so a crashed tool never passes for a clean tree. Full guide: docs/github-action.md.

How it works

C / C++ ──clang──▶ LLVM IR (in memory) ──▶ facts ──▶ interprocedural propagation ──▶ rules ──▶ text · JSON · SARIF
                                            (threads, locks,   (thread reachability,
                                             accesses, forks)   lifecycle, held locks)

Sources are compiled unoptimized so the analysis sees the program as written. In project mode, seven kinds of facts cross translation-unit boundaries (docs/cross-tu-mode.md).

Known limits — shared state reached through heap or stack pointers is not tracked yet (only globals are), and thread entries passed as pointer-to-member are not resolved. Details in docs/rules.md.

Use it as a library

llvm::LLVMContext context;
ctrace::concurrency::InMemoryIRCompiler compiler;
auto result = compiler.compile({.inputFile = "sample.cpp"}, context);

ctrace::concurrency::SingleTUConcurrencyAnalyzer analyzer;
auto report = analyzer.analyze(*result.module);

// What a finding's rule detects, with the text the reports give it.
auto rule = ctrace::concurrency::describeRule(report.diagnostics.front().ruleId);
// rule.title, rule.description, rule.defaultSeverity

Embed it with CMake FetchContent (tag v0.8.0); a complete consumer lives in extern-project/. API reference: docs/api.md.

Building

LLVM=/opt/homebrew/opt/llvm@20   # or /usr/lib/llvm-20 on Debian/Ubuntu
cmake -S . -B build \
  -DLLVM_DIR=$LLVM/lib/cmake/llvm \
  -DClang_DIR=$LLVM/lib/cmake/clang \
  -DCLANG_EXECUTABLE=$LLVM/bin/clang \
  -DCLANG_RESOURCE_DIR=$LLVM/lib/clang/20
cmake --build build -j
ctest --test-dir build --output-on-failure

Documentation

Rules & limits what each rule establishes and does not
CLI reference options, output formats, exit codes
GitHub Action workflows, inputs, outputs, false positives
Project mode whole-program analysis from compile_commands.json
Performance cost on a real 49-unit project
Architecture layers, backend, extension points

Contributing

Issues and PRs welcome — see CONTRIBUTING.md. Part of the CoreTrace toolset, alongside coretrace-stack-analyzer.

Licensed under Apache 2.0.

About

Is a static concurrency analysis tool for C and C++ that helps detect threading and synchronization bugs before runtime. It focuses on shared-state correctness, lock discipline, thread lifecycle validation, and atomic usage analysis to surface race-prone patterns, missing synchronization, and structural concurrency flaws in a CI-friendly way.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages