Current overview of DataFlowBench
Each kernel panel keeps one analyzer within one language's own denominator. Its bar label and confusion-matrix dialog list decisive, inconclusive, unsupported, and runner-error counts separately; unsupported alone is a declared decline.
Each kernel poses one positive and one negative assertion per semantic template, and each language's kernel is its own population — cores of 28, 31, 33, 34 or 35 templates, never pooled or ranked against each other, and never compared with the smaller cores of an earlier snapshot. Because every pair is balanced, an analyzer that always answers the same way — or answers blindly where it cannot see a construct — scores exactly half on the affected pairs: read correctness against that 50% blind baseline, and read approximation character from each vendor's TPR/FPR split in the details dialog. A blank analyzer on a kernel means no report in this freeze: no extractor, no frontend, or no adapter, which is coverage rather than a score.
DataFlowBench is SlopCop's own benchmark for semantic data flow: we build it to measure where Bifrost stands against 7 reference analyzers, and to keep ourselves honest while doing it. The methodology is deliberately analyzer-neutral — every number here is generated from digest-bound freeze evidence that we cannot edit after the fact, misses and crashes included — but the motivation is not neutral, and we would rather say so.
What v0.9.2 contains
This fixed-configuration snapshot records the v0.9.2 release model and its retained outcomes. Bifrost was measured at v0.15.1. Inconclusive results preserve incomplete proof; unsupported results record declared coverage; runner errors record failed executions. None becomes a negative finding. CodeQL's native Java, JavaScript, and Python profiles include query-pack lookup runner errors, documented in the case-variation note. The generated figures beside this text come from this snapshot's model.
Below the kernels sit two further populations: the modeling matrix, which asks whether each tool's own model-declaration surface is load-bearing, and the tool-native probes, which ask what each product decides with nothing supplied by us. No certified latency corpus is published for these pins. A separate diagnostic timing supplement records candidate observations without changing the frozen results. The v0.9.0 latency page remains bound to its older pins. All populations have separate denominators. There is no combined leaderboard, and benchmark-controlled results are never pooled with, or compared number-to-number against, tool-native ones.
On the direct-flow breadth baseline, Bifrost answered both assertions correctly in 13 of 13 languages.
- Frozen case results, across three populations
- 4,252
- Kernel languages, 28, 31, 33, 34 or 35 templates each
- 14
- Languages in the direct-flow breadth baseline
- 13
- Immutable evidence release
- v0.9.2
How decisive, and how correct
Overall decisiveness uses all 952 assertions in the 13 kernel corpus as every analyzer's denominator; a language with no analyzer entry therefore remains visible as unanswered coverage.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered |
|---|---|---|---|
| Bifrost | 528/952 (55.5%) | 527/528 (99.8%) | 424 |
| CodeQL | 740/952 (77.7%) | 594/740 (80.3%) | 212 |
| Joern | 350/952 (36.8%) | 274/350 (78.3%) | 602 |
| Semgrep CE | 154/952 (16.2%) | 132/154 (85.7%) | 798 |
| OpenTaint | 140/952 (14.7%) | 121/140 (86.4%) | 812 |
| Infer | 194/952 (20.4%) | 157/194 (80.9%) | 758 |
| FlowDroid | 140/952 (14.7%) | 122/140 (87.1%) | 812 |
| Pysa | 70/952 (7.4%) | 56/70 (80.0%) | 882 |
c is its own 56-assertion population. Analyzers without a c kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 42/56 (75.0%) | 42/42 (100.0%) | 14 | |
| CodeQL | 55/56 (98.2%) | 47/55 (85.5%) | 1 | |
| Semgrep CE | 14/56 (25.0%) | 12/14 (85.7%) | 42 | |
| Infer | 56/56 (100.0%) | 47/56 (83.9%) | 0 |
cpp is its own 68-assertion population. Analyzers without a cpp kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 30/68 (44.1%) | 30/30 (100.0%) | 38 | |
| CodeQL | 67/68 (98.5%) | 50/67 (74.6%) | 1 | |
| Semgrep CE | 14/68 (20.6%) | 12/14 (85.7%) | 54 | |
| Infer | 68/68 (100.0%) | 53/68 (77.9%) | 0 |
csharp is its own 70-assertion population. Analyzers without a csharp kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 44/70 (62.9%) | 43/44 (97.7%) | 26 | |
| CodeQL | 69/70 (98.6%) | 55/69 (79.7%) | 1 |
go is its own 70-assertion population. Analyzers without a go kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 44/70 (62.9%) | 44/44 (100.0%) | 26 | |
| CodeQL | 69/70 (98.6%) | 54/69 (78.3%) | 1 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 |
java is its own 70-assertion population. Analyzers without a java kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 46/70 (65.7%) | 46/46 (100.0%) | 24 | |
| CodeQL | 70/70 (100.0%) | 57/70 (81.4%) | 0 | |
| Joern | 70/70 (100.0%) | 57/70 (81.4%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 | |
| OpenTaint | 70/70 (100.0%) | 61/70 (87.1%) | 0 | |
| Infer | 70/70 (100.0%) | 57/70 (81.4%) | 0 | |
| FlowDroid | 70/70 (100.0%) | 61/70 (87.1%) | 0 |
javascript is its own 70-assertion population. Analyzers without a javascript kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 48/70 (68.6%) | 48/48 (100.0%) | 22 | |
| CodeQL | 70/70 (100.0%) | 57/70 (81.4%) | 0 | |
| Joern | 70/70 (100.0%) | 55/70 (78.6%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 |
kotlin is its own 70-assertion population. Analyzers without a kotlin kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 32/70 (45.7%) | 32/32 (100.0%) | 38 | |
| CodeQL | 70/70 (100.0%) | 55/70 (78.6%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 | |
| OpenTaint | 70/70 (100.0%) | 60/70 (85.7%) | 0 | |
| FlowDroid | 70/70 (100.0%) | 61/70 (87.1%) | 0 |
php is its own 70-assertion population. Analyzers without a php kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 34/70 (48.6%) | 34/34 (100.0%) | 36 | |
| Joern | 70/70 (100.0%) | 58/70 (82.9%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 |
python is its own 70-assertion population. Analyzers without a python kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 42/70 (60.0%) | 42/42 (100.0%) | 28 | |
| CodeQL | 69/70 (98.6%) | 56/69 (81.2%) | 1 | |
| Joern | 70/70 (100.0%) | 58/70 (82.9%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 | |
| Pysa | 70/70 (100.0%) | 56/70 (80.0%) | 0 |
ruby is its own 70-assertion population. Analyzers without a ruby kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 36/70 (51.4%) | 36/36 (100.0%) | 34 | |
| CodeQL | 69/70 (98.6%) | 57/69 (82.6%) | 1 | |
| Joern | 70/70 (100.0%) | 46/70 (65.7%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 |
rust is its own 62-assertion population. Analyzers without a rust kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 42/62 (67.7%) | 42/42 (100.0%) | 20 | |
| CodeQL | 62/62 (100.0%) | 49/62 (79.0%) | 0 | |
| Joern | 0/62 (0.0%) | 0/0 (0.0%) | 62 | |
| Semgrep CE | 14/62 (22.6%) | 12/14 (85.7%) | 48 |
scala is its own 70-assertion population. Analyzers without a scala kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 42/70 (60.0%) | 42/42 (100.0%) | 28 |
swift is its own 66-assertion population. Analyzers without a swift kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| CodeQL | 0/66 (0.0%) | 0/0 (0.0%) | 66 | |
| Joern | 0/66 (0.0%) | 0/0 (0.0%) | 66 |
typescript is its own 70-assertion population. Analyzers without a typescript kernel entry are absent, never plotted as zero.
Exact figures
| Analyzer | Decisiveness | Correctness when decisive | Unanswered | Evidence |
|---|---|---|---|---|
| Bifrost | 46/70 (65.7%) | 46/46 (100.0%) | 24 | |
| CodeQL | 70/70 (100.0%) | 57/70 (81.4%) | 0 | |
| Semgrep CE | 14/70 (20.0%) | 12/14 (85.7%) | 56 |
What this result means
DataFlowBench measures whether analyzers correctly decide semantic
data-flow questions — and whether they stay quiet when they should. Cases
are balanced positive/negative pairs of language-neutral semantic templates
(aliasing, kills, call context, branch joins, exception paths, …). The
kernels and the modeling matrix run under a
benchmark-controlled model profile, so the engines are compared
under a common contract; the tool-native probes run under a
tool-native profile, measuring the shipped product instead. The
two profiles answer different questions and are never combined.
This snapshot's bounded claim covers the synthetic direct-flow breadth
baseline and the propagation kernels of the 14 kernel
languages above on the taint track, plus the modeling matrix
and the tool-native probe set in java, javascript, and python. Cores are
sized per language (28, 31, 33, 34 or 35 templates), so each kernel is read on
its own denominator; language-only constructs are reported in separate
language-extension tiers on the snapshot pages. It does not
estimate real-project accuracy or other languages' kernel behavior;
performance never enters these scores. Raw durations remain in retained execution evidence, without a published
latency corpus or certified current timing comparison. The tool-native rows describe shipped coverage on six
probe templates rather than product accuracy at large.
inconclusive preserves incomplete proof,
unsupported records declared coverage, and
runner-error records failed execution; none becomes a clean
negative.
Accuracy and language coverage — current snapshot
Every analyzer is shown in the same field. Farther right means documented data-flow support for more languages; higher means more correct assertions within the kernels the analyzer covers. A specialist can therefore show its accuracy without hiding the cost of its narrower language support. The horizontal axis is an analyzer capability, not a count of the adapters DataFlowBench happens to implement. Benchmark kernel participation remains visible in the exact figures below. These are two independent dimensions, not a combined score.
- generalist
- specialist
Exact figures
| Analyzer | Scope | Supported languages | Benchmark kernels | Accuracy | Correct | Wrong | Incomplete |
|---|---|---|---|---|---|---|---|
| Bifrost | generalist | 13C, C++, C#, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, Scala, TypeScript | 13/14 (92.9%) | 527/886 (59.5%) | 527 | 1 | 358 |
| CodeQL | generalist | 12C, C++, C#, Go, Java, JavaScript, Kotlin, Python, Ruby, Rust, Swift, TypeScript | 12/14 (85.7%) | 594/812 (73.2%) | 594 | 146 | 72 |
| Joern | generalist | 11C, C++, C#, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Swift | 7/14 (50.0%) | 274/478 (57.3%) | 274 | 76 | 128 |
| Semgrep CE | generalist | 11C, C++, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, Rust, TypeScript | 11/14 (78.6%) | 132/746 (17.7%) | 132 | 22 | 592 |
| OpenTaint | specialist | 2Java, Kotlin | 2/14 (14.3%) | 121/140 (86.4%) | 121 | 19 | 0 |
| Infer | specialist | 3C, C++, Java | 3/14 (21.4%) | 157/194 (80.9%) | 157 | 37 | 0 |
| FlowDroid | specialist | 2Java, Kotlin | 2/14 (14.3%) | 122/140 (87.1%) | 122 | 18 | 0 |
| Pysa | specialist | 1Python | 1/14 (7.1%) | 56/70 (80.0%) | 56 | 14 | 0 |
Modeling matrix — is the model surface load-bearing?
A separate population from the kernels above, on the same
benchmark-controlled profile. Twelve preregistered templates in
six balanced categories — declared sources and sinks, declared propagators,
declared sanitizers, opaque summaries, framework entry points, persistence
boundaries — ask whether each tool's own model-declaration surface
can express a category and be made to carry the flow. A category a tool
cannot express is unsupported, decided before
the tool is invoked. The scored partition differs per adapter, so the
denominators differ by construction and are never pooled or ranked.
Read the scored column first: it is the load-bearing number, and the
ratio inside it is only meaningful against that tool's own partition.
Bifrost 0.15.1
CodeQL 2.27.2
Joern 4.0.660
Semgrep CE 1.181.0
OpenTaint v0.4.6
Infer v1.3.0
FlowDroid 2.15.1
Pysa 0.10.0
Read the scored partition, not the ratio: across the 18
language tiers it runs from 8 to 24 of the
24 assertions in the tier, so no two of these bars are
the same exam. The per-tier counts behind every bar are on the
analyzers page, and the
template-by-template model-* outcomes on the
semantic templates page.
Tool-native probes — what ships and decides on its own
A third population, under the tool-native model profile: six
templates run with nothing supplied by DataFlowBench, against
whatever ruleset, semantics, or policy pack the product ships. This measures
product coverage, not engine accuracy.
Tool-native results are never pooled with the benchmark-controlled kernels
or the modeling matrix, and never compared number-to-number with them.
A tier that is entirely unsupported is a
declared decline — the tool ships no source or sink catalog for it — and is
never counted as a wrong answer. A runner-error remains a
separate failed execution, not a decline or negative finding. Those runs
still witness the identity of the binary and
ruleset that produced them.
Bifrost 0.15.1
CodeQL 2.27.2
Joern 4.0.660
Semgrep CE 1.181.0
OpenTaint v0.4.6
Infer v1.3.0
FlowDroid 2.15.1
Pysa 0.10.0
12 of the 18 tiers are entirely
unsupported — declared declines, never zero scores. 2
tiers produce at least one decisive answer (24 assertions
across Pysa and Semgrep CE); 4
other tiers have no decisive answer. Runner errors and inconclusive outcomes
remain separately counted on each row. Per-tier coverage is
on the analyzers page, the
native-* template outcomes on the
semantic templates page, and every
case — including the runs that decide nothing — on the
case evidence page.
Current timing evidence
Descriptive roll-up of retained invocation records. No timing is certified. 21 of 84 planned cold groups have retained reports; 18 groups contain timed invocations; 1,085 of 1,170 retained report rows have a wall-time observation. The 85 unsupported rows have no timed invocation; 338 timed rows have inconclusive outcomes. A recorded duration does not certify successful analysis. This is the 13 November 2026 capture. Rows follow the frozen v0.9.2 analyzer order and pins.
Each analyzer's distribution is computed from its raw per-case observations. It combines mixed languages, tiers, populations and profiles, so it is not a matched comparison, performance ranking or certification. The six analyzers without retained cold reports are shown with their recorded runtime blockers.
8 analyzers · 21 / 84 groups captured · 1,085 / 1,170 report rows timed
- Bifrost v0.15.1 At capture: Pinned Scala Maven materialization must be restored and verified.961 / 1,046 timed · 19 / 20 groups
- CodeQL CLI 2.27.2 · frozen packs At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 18 groups captured
- Joern 4.0.660 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 13 groups captured
- Semgrep CE 1.181.0 · rules 17e31e11… At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 17 groups captured
- OpenTaint 0.4.6 · analyzer 2026.09.04.c51dc3e At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 4 groups captured
- Infer v1.3.0 At capture: Pinned /usr/bin/java or javac digest differs on this OS.124 / 124 timed · 2 / 5 groups
- FlowDroid 2.15.1 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 4 groups captured
- Pysa / pyre-check 0.10.0 · Pyrefly 1.4.0 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- Bifrost v0.15.1 At capture: Pinned Scala Maven materialization must be restored and verified.820 / 820 timed · 12 / 13 groups
- CodeQL CLI 2.27.2 · frozen packs At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 12 groups captured
- Joern 4.0.660 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 7 groups captured
- Semgrep CE 1.181.0 · rules 17e31e11… At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 11 groups captured
- OpenTaint 0.4.6 · analyzer 2026.09.04.c51dc3e At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 2 groups captured
- Infer v1.3.0 At capture: Pinned /usr/bin/java or javac digest differs on this OS.124 / 124 timed · 2 / 3 groups
- FlowDroid 2.15.1 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 2 groups captured
- Pysa / pyre-check 0.10.0 · Pyrefly 1.4.0 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 1 groups captured
- Bifrost v0.15.124 / 72 timed · 3 / 3 groups
- CodeQL CLI 2.27.2 · frozen packs At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- Joern 4.0.660 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- Semgrep CE 1.181.0 · rules 17e31e11… At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- OpenTaint 0.4.6 · analyzer 2026.09.04.c51dc3e At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- Infer v1.3.0 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- FlowDroid 2.15.1 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- Pysa / pyre-check 0.10.0 · Pyrefly 1.4.0 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 1 groups captured
- Bifrost v0.15.10 / 36 timed · 3 / 3 groups
- CodeQL CLI 2.27.2 · frozen packs At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- Joern 4.0.660 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- Semgrep CE 1.181.0 · rules 17e31e11… At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 3 groups captured
- OpenTaint 0.4.6 · analyzer 2026.09.04.c51dc3e At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- Infer v1.3.0 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- FlowDroid 2.15.1 At capture: Pinned /usr/bin/java or javac digest differs on this OS.0 / 1 groups captured
- Pysa / pyre-check 0.10.0 · Pyrefly 1.4.0 At capture: Exact v0.9.2 runtime closure is missing from its bound paths; restoration and verification are pending.0 / 1 groups captured
- Bifrost v0.15.1117 / 118 timed · 1 / 1 groups
- CodeQL CLI 2.27.2 · frozen packs0 / 0 timed · 0 / 0 groups
- Joern 4.0.6600 / 0 timed · 0 / 0 groups
- Semgrep CE 1.181.0 · rules 17e31e11…0 / 0 timed · 0 / 0 groups
- OpenTaint 0.4.6 · analyzer 2026.09.04.c51dc3e0 / 0 timed · 0 / 0 groups
- Infer v1.3.00 / 0 timed · 0 / 0 groups
- FlowDroid 2.15.10 / 0 timed · 0 / 0 groups
- Pysa / pyre-check 0.10.0 · Pyrefly 1.4.00 / 0 timed · 0 / 0 groups
- Bifrost · C kernel 58 / 58 timed
- Bifrost · C++ kernel 68 / 68 timed
- Bifrost · C# kernel 70 / 70 timed
- Bifrost · Go kernel 70 / 70 timed
- Bifrost · Java kernel 70 / 70 timed
- Bifrost · Java modeling 8 / 24 timed
- Bifrost · Java native 0 / 12 timed
- Bifrost · JavaScript kernel 70 / 70 timed
- Bifrost · JavaScript modeling 8 / 24 timed
- Bifrost · JavaScript native 0 / 12 timed
- Bifrost · Kotlin kernel 70 / 70 timed
- Bifrost · PHP kernel 70 / 70 timed
- Bifrost · Python kernel 70 / 70 timed
- Bifrost · Python modeling 8 / 24 timed
- Bifrost · Python native 0 / 12 timed
- Bifrost · Ruby kernel 70 / 70 timed
- Bifrost · Rust kernel 64 / 64 timed
- Bifrost · mixed languages smoke 117 / 118 timed
- Bifrost · TypeScript kernel 70 / 70 timed
- Infer · C kernel 56 / 56 timed
- Infer · C++ kernel 68 / 68 timed
No retained slice records match these filters. This is missing timing coverage, not unsupported analysis.
These values summarize different case invocations, not repeated trials or runtime variance. The Bifrost C cold record retained a passing initial quiet-gate flag; later cold records retained false flags because no renewed per-group quiet checks were made. Contention was observed in Bifrost C and Java cold records, and Bifrost Python overhead only. No CPU observation failures were recorded (0). A24 inter-adapter settling was omitted for the overhead measurements. Process-descendant containment remains unproven, and every recorded certification flag remains false.
Separate invocation-overhead estimates: Bifrost / Python 562 ms–805 ms (contention observed); Infer / C 245 ms–260 ms (no contention observed). Three repeats each; ranges are upper-bound estimates including analysis of no-flow fixtures, not warm marginal cost. Nothing is subtracted from the cold chart.
Full timing tables, qualification and downloadable evidence
Timing values for all 21 captured slices
Rounded for readability. This table always shows the retained per-slice values, regardless of chart filters. A dash means no timing, never zero; full precision is retained in the downloadable evidence.
| Slice | Timed / report rows | Minimum | Median | 90th percentile | Maximum |
|---|---|---|---|---|---|
| Bifrost · C kernel | 58 / 58 | 559 ms | 598 ms | 631 ms | 1.16 s |
| Bifrost · C++ kernel | 68 / 68 | 591 ms | 609 ms | 634 ms | 1.1 s |
| Bifrost · C# kernel | 70 / 70 | 593 ms | 613 ms | 635 ms | 1 s |
| Bifrost · Go kernel | 70 / 70 | 697 ms | 725 ms | 758 ms | 1.18 s |
| Bifrost · Java kernel | 70 / 70 | 1.35 s | 1.38 s | 1.41 s | 8.36 s |
| Bifrost · Java modeling | 8 / 24 | 1.38 s | 1.4 s | 3.45 s | 8.14 s |
| Bifrost · Java native | 0 / 12 | — | — | — | — |
| Bifrost · JavaScript kernel | 70 / 70 | 596 ms | 610 ms | 631 ms | 980 ms |
| Bifrost · JavaScript modeling | 8 / 24 | 591 ms | 612 ms | 734 ms | 987 ms |
| Bifrost · JavaScript native | 0 / 12 | — | — | — | — |
| Bifrost · Kotlin kernel | 70 / 70 | 1.39 s | 1.46 s | 1.57 s | 8.16 s |
| Bifrost · PHP kernel | 70 / 70 | 595 ms | 611 ms | 634 ms | 1.01 s |
| Bifrost · Python kernel | 70 / 70 | 591 ms | 605 ms | 625 ms | 967 ms |
| Bifrost · Python modeling | 8 / 24 | 593 ms | 608 ms | 737 ms | 995 ms |
| Bifrost · Python native | 0 / 12 | — | — | — | — |
| Bifrost · Ruby kernel | 70 / 70 | 588 ms | 603 ms | 621 ms | 976 ms |
| Bifrost · Rust kernel | 64 / 64 | 655 ms | 679 ms | 723 ms | 1.09 s |
| Bifrost · mixed languages smoke | 117 / 118 | 603 ms | 629 ms | 1.41 s | 7.75 s |
| Bifrost · TypeScript kernel | 70 / 70 | 598 ms | 613 ms | 630 ms | 1.01 s |
| Infer · C kernel | 56 / 56 | 254 ms | 263 ms | 281 ms | 964 ms |
| Infer · C++ kernel | 68 / 68 | 258 ms | 268 ms | 1.63 s | 1.82 s |
Progress over time
How the benchmark and its analyzers evolved
Generalists
One line per analyzer across every freeze. The vertical axis counts decisive-correct assertions; the grey step is the full benchmark core, which grew from 32 assertions in v0.1.0 to 952 in v0.9.2. Nothing is pooled with other result profiles or turned into a combined score.
- Bifrost · decisive-correct
- CodeQL · decisive-correct
- Joern · decisive-correct
- Semgrep CE · decisive-correct
- benchmark core population (the denominator)
- remainder of that analyzer's own covered population
- Bifrost · decisive-correct ÷ its covered population
- CodeQL · decisive-correct ÷ its covered population
- Joern · decisive-correct ÷ its covered population
- Semgrep CE · decisive-correct ÷ its covered population
- marker size and the
k/nlabel under it: kernels covered of the snapshot's kernels
Marker: decisive-correct. Cap or stub: that analyzer's covered population.
Grey step: the full core population. The covered-kernel view keeps
non-answers in its denominator and shows coverage as k/n;
missing runs are absent, never zero. Exact figures are in the table.
| Snapshot | Analyzer | Decisive-correct | Decided | Coverage outcomes | Its covered population | Correct ÷ its covered population | Benchmark core population | Secondary: correct ÷ decided |
|---|---|---|---|---|---|---|---|---|
| v0.1.0 | Bifrost | 17 | 22 | 10 | 32(1 of 1 kernel) | 53.1%(17 of 32 covered, 1 of 1 kernel) | 32 | 77.3% (17 of 22 decided) |
| v0.1.0 | CodeQL | 27 | 32 | 0 | 32(1 of 1 kernel) | 84.4%(27 of 32 covered, 1 of 1 kernel) | 32 | 84.4% (27 of 32 decided) |
| v0.2.0 | Bifrost | 52 | 68 | 28 | 96(3 of 3 kernels) | 54.2%(52 of 96 covered, 3 of 3 kernels) | 96 | 76.5% (52 of 68 decided) |
| v0.2.0 | CodeQL | 84 | 96 | 0 | 96(3 of 3 kernels) | 87.5%(84 of 96 covered, 3 of 3 kernels) | 96 | 87.5% (84 of 96 decided) |
| v0.3.0 | Bifrost | 163 | 166 | 150 | 316(10 of 10 kernels) | 51.6%(163 of 316 covered, 10 of 10 kernels) | 316 | 98.2% (163 of 166 decided) |
| v0.3.0 | CodeQL | 276 | 316 | 0 | 316(10 of 10 kernels) | 87.3%(276 of 316 covered, 10 of 10 kernels) | 316 | 87.3% (276 of 316 decided) |
| v0.4.0 | Bifrost | 222 | 227 | 511 | 738(13 of 13 kernels) | 30.1%(222 of 738 covered, 13 of 13 kernels) | 738 | 97.8% (222 of 227 decided) |
| v0.4.0 | CodeQL | 506 | 622 | 0 | 622(11 of 13 kernels) | 81.4%(506 of 622 covered, 11 of 13 kernels) | 738 | 81.4% (506 of 622 decided) |
| v0.4.0 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.4.0 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.5.0 | Bifrost | 435 | 440 | 298 | 738(13 of 13 kernels) | 58.9%(435 of 738 covered, 13 of 13 kernels) | 738 | 98.9% (435 of 440 decided) |
| v0.5.0 | CodeQL | 506 | 622 | 0 | 622(11 of 13 kernels) | 81.4%(506 of 622 covered, 11 of 13 kernels) | 738 | 81.4% (506 of 622 decided) |
| v0.5.0 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.5.0 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.6.0 | Bifrost | 435 | 440 | 298 | 738(13 of 13 kernels) | 58.9%(435 of 738 covered, 13 of 13 kernels) | 738 | 98.9% (435 of 440 decided) |
| v0.6.0 | CodeQL | 506 | 622 | 0 | 622(11 of 13 kernels) | 81.4%(506 of 622 covered, 11 of 13 kernels) | 738 | 81.4% (506 of 622 decided) |
| v0.6.0 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.6.0 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.6.1 | Bifrost | 446 | 446 | 292 | 738(13 of 13 kernels) | 60.4%(446 of 738 covered, 13 of 13 kernels) | 738 | 100.0% (446 of 446 decided) |
| v0.6.1 | CodeQL | 506 | 622 | 0 | 622(11 of 13 kernels) | 81.4%(506 of 622 covered, 11 of 13 kernels) | 738 | 81.4% (506 of 622 decided) |
| v0.6.1 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.6.1 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.7.0 | Bifrost | 450 | 450 | 288 | 738(13 of 13 kernels) | 61.0%(450 of 738 covered, 13 of 13 kernels) | 738 | 100.0% (450 of 450 decided) |
| v0.7.0 | CodeQL | 501 | 617 | 5 | 622(11 of 13 kernels) | 80.5%(501 of 622 covered, 11 of 13 kernels) | 738 | 81.2% (501 of 617 decided) |
| v0.7.0 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.7.0 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.7.1 | Bifrost | 452 | 452 | 286 | 738(13 of 13 kernels) | 61.2%(452 of 738 covered, 13 of 13 kernels) | 738 | 100.0% (452 of 452 decided) |
| v0.7.1 | CodeQL | 501 | 617 | 5 | 622(11 of 13 kernels) | 80.5%(501 of 622 covered, 11 of 13 kernels) | 738 | 81.2% (501 of 617 decided) |
| v0.7.1 | Joern | 270 | 344 | 0 | 344(6 of 13 kernels) | 78.5%(270 of 344 covered, 6 of 13 kernels) | 738 | 78.5% (270 of 344 decided) |
| v0.7.1 | Semgrep CE | 132 | 154 | 468 | 622(11 of 13 kernels) | 21.2%(132 of 622 covered, 11 of 13 kernels) | 738 | 85.7% (132 of 154 decided) |
| v0.8.0 | Bifrost | 494 | 494 | 392 | 886(13 of 13 kernels) | 55.8%(494 of 886 covered, 13 of 13 kernels) | 886 | 100.0% (494 of 494 decided) |
| v0.8.0 | CodeQL | 499 | 619 | 127 | 746(11 of 13 kernels) | 66.9%(499 of 746 covered, 11 of 13 kernels) | 886 | 80.6% (499 of 619 decided) |
| v0.8.0 | Joern | 323 | 412 | 0 | 412(6 of 13 kernels) | 78.4%(323 of 412 covered, 6 of 13 kernels) | 886 | 78.4% (323 of 412 decided) |
| v0.8.0 | Semgrep CE | 132 | 154 | 592 | 746(11 of 13 kernels) | 17.7%(132 of 746 covered, 11 of 13 kernels) | 886 | 85.7% (132 of 154 decided) |
| v0.9.0 | Bifrost | 524 | 524 | 362 | 886(13 of 14 kernels) | 59.1%(524 of 886 covered, 13 of 14 kernels) | 952 | 100.0% (524 of 524 decided) |
| v0.9.0 | CodeQL | 596 | 741 | 71 | 812(12 of 14 kernels) | 73.4%(596 of 812 covered, 12 of 14 kernels) | 952 | 80.4% (596 of 741 decided) |
| v0.9.0 | Joern | 323 | 412 | 66 | 478(7 of 14 kernels) | 67.6%(323 of 478 covered, 7 of 14 kernels) | 952 | 78.4% (323 of 412 decided) |
| v0.9.0 | Semgrep CE | 132 | 154 | 592 | 746(11 of 14 kernels) | 17.7%(132 of 746 covered, 11 of 14 kernels) | 952 | 85.7% (132 of 154 decided) |
| v0.9.2 | Bifrost | 527 | 528 | 358 | 886(13 of 14 kernels) | 59.5%(527 of 886 covered, 13 of 14 kernels) | 952 | 99.8% (527 of 528 decided) |
| v0.9.2 | CodeQL | 594 | 740 | 72 | 812(12 of 14 kernels) | 73.2%(594 of 812 covered, 12 of 14 kernels) | 952 | 80.3% (594 of 740 decided) |
| v0.9.2 | Joern | 274 | 350 | 128 | 478(7 of 14 kernels) | 57.3%(274 of 478 covered, 7 of 14 kernels) | 952 | 78.3% (274 of 350 decided) |
| v0.9.2 | Semgrep CE | 132 | 154 | 592 | 746(11 of 14 kernels) | 17.7%(132 of 746 covered, 11 of 14 kernels) | 952 | 85.7% (132 of 154 decided) |
The exact values behind both chart views, one row per analyzer and snapshot.
Specialists
Analyzers deliberately focused on one ecosystem or a small related family, separated because breadth and specialization are not directly comparable. Uses the same percentage axis as the generalists' covered-kernel view.
- OpenTaint · decisive-correct ÷ its covered population
- Infer · decisive-correct ÷ its covered population
- FlowDroid · decisive-correct ÷ its covered population
- Pysa · decisive-correct ÷ its covered population
- marker size and the
k/nlabel under it: kernels covered of the snapshot's kernels
Same scales and encoding as the generalists. The covered-kernel view keeps
specialist scope visible as k/n; exact figures are in the table.
| Snapshot | Analyzer | Decisive-correct | Decided | Coverage outcomes | Its covered population | Correct ÷ its covered population | Benchmark core population | Secondary: correct ÷ decided |
|---|---|---|---|---|---|---|---|---|
| v0.6.0 | OpenTaint | 99 | 116 | 0 | 116(2 of 13 kernels) | 85.3%(99 of 116 covered, 2 of 13 kernels) | 738 | 85.3% (99 of 116 decided) |
| v0.6.0 | Infer | 140 | 162 | 0 | 162(3 of 13 kernels) | 86.4%(140 of 162 covered, 3 of 13 kernels) | 738 | 86.4% (140 of 162 decided) |
| v0.6.0 | FlowDroid | 98 | 116 | 0 | 116(2 of 13 kernels) | 84.5%(98 of 116 covered, 2 of 13 kernels) | 738 | 84.5% (98 of 116 decided) |
| v0.6.0 | Pysa | 47 | 58 | 0 | 58(1 of 13 kernels) | 81.0%(47 of 58 covered, 1 of 13 kernels) | 738 | 81.0% (47 of 58 decided) |
| v0.6.1 | OpenTaint | 99 | 116 | 0 | 116(2 of 13 kernels) | 85.3%(99 of 116 covered, 2 of 13 kernels) | 738 | 85.3% (99 of 116 decided) |
| v0.6.1 | Infer | 140 | 162 | 0 | 162(3 of 13 kernels) | 86.4%(140 of 162 covered, 3 of 13 kernels) | 738 | 86.4% (140 of 162 decided) |
| v0.6.1 | FlowDroid | 98 | 116 | 0 | 116(2 of 13 kernels) | 84.5%(98 of 116 covered, 2 of 13 kernels) | 738 | 84.5% (98 of 116 decided) |
| v0.6.1 | Pysa | 47 | 58 | 0 | 58(1 of 13 kernels) | 81.0%(47 of 58 covered, 1 of 13 kernels) | 738 | 81.0% (47 of 58 decided) |
| v0.7.0 | OpenTaint | 99 | 116 | 0 | 116(2 of 13 kernels) | 85.3%(99 of 116 covered, 2 of 13 kernels) | 738 | 85.3% (99 of 116 decided) |
| v0.7.0 | Infer | 140 | 162 | 0 | 162(3 of 13 kernels) | 86.4%(140 of 162 covered, 3 of 13 kernels) | 738 | 86.4% (140 of 162 decided) |
| v0.7.0 | FlowDroid | 98 | 116 | 0 | 116(2 of 13 kernels) | 84.5%(98 of 116 covered, 2 of 13 kernels) | 738 | 84.5% (98 of 116 decided) |
| v0.7.0 | Pysa | 47 | 58 | 0 | 58(1 of 13 kernels) | 81.0%(47 of 58 covered, 1 of 13 kernels) | 738 | 81.0% (47 of 58 decided) |
| v0.7.1 | OpenTaint | 101 | 116 | 0 | 116(2 of 13 kernels) | 87.1%(101 of 116 covered, 2 of 13 kernels) | 738 | 87.1% (101 of 116 decided) |
| v0.7.1 | Infer | 140 | 162 | 0 | 162(3 of 13 kernels) | 86.4%(140 of 162 covered, 3 of 13 kernels) | 738 | 86.4% (140 of 162 decided) |
| v0.7.1 | FlowDroid | 98 | 116 | 0 | 116(2 of 13 kernels) | 84.5%(98 of 116 covered, 2 of 13 kernels) | 738 | 84.5% (98 of 116 decided) |
| v0.7.1 | Pysa | 47 | 58 | 0 | 58(1 of 13 kernels) | 81.0%(47 of 58 covered, 1 of 13 kernels) | 738 | 81.0% (47 of 58 decided) |
| v0.8.0 | OpenTaint | 121 | 140 | 0 | 140(2 of 13 kernels) | 86.4%(121 of 140 covered, 2 of 13 kernels) | 886 | 86.4% (121 of 140 decided) |
| v0.8.0 | Infer | 157 | 194 | 0 | 194(3 of 13 kernels) | 80.9%(157 of 194 covered, 3 of 13 kernels) | 886 | 80.9% (157 of 194 decided) |
| v0.8.0 | FlowDroid | 122 | 140 | 0 | 140(2 of 13 kernels) | 87.1%(122 of 140 covered, 2 of 13 kernels) | 886 | 87.1% (122 of 140 decided) |
| v0.8.0 | Pysa | 56 | 70 | 0 | 70(1 of 13 kernels) | 80.0%(56 of 70 covered, 1 of 13 kernels) | 886 | 80.0% (56 of 70 decided) |
| v0.9.0 | OpenTaint | 121 | 140 | 0 | 140(2 of 14 kernels) | 86.4%(121 of 140 covered, 2 of 14 kernels) | 952 | 86.4% (121 of 140 decided) |
| v0.9.0 | Infer | 157 | 194 | 0 | 194(3 of 14 kernels) | 80.9%(157 of 194 covered, 3 of 14 kernels) | 952 | 80.9% (157 of 194 decided) |
| v0.9.0 | FlowDroid | 122 | 140 | 0 | 140(2 of 14 kernels) | 87.1%(122 of 140 covered, 2 of 14 kernels) | 952 | 87.1% (122 of 140 decided) |
| v0.9.0 | Pysa | 56 | 70 | 0 | 70(1 of 14 kernels) | 80.0%(56 of 70 covered, 1 of 14 kernels) | 952 | 80.0% (56 of 70 decided) |
| v0.9.2 | OpenTaint | 121 | 140 | 0 | 140(2 of 14 kernels) | 86.4%(121 of 140 covered, 2 of 14 kernels) | 952 | 86.4% (121 of 140 decided) |
| v0.9.2 | Infer | 157 | 194 | 0 | 194(3 of 14 kernels) | 80.9%(157 of 194 covered, 3 of 14 kernels) | 952 | 80.9% (157 of 194 decided) |
| v0.9.2 | FlowDroid | 122 | 140 | 0 | 140(2 of 14 kernels) | 87.1%(122 of 140 covered, 2 of 14 kernels) | 952 | 87.1% (122 of 140 decided) |
| v0.9.2 | Pysa | 56 | 70 | 0 | 70(1 of 14 kernels) | 80.0%(56 of 70 covered, 1 of 14 kernels) | 952 | 80.0% (56 of 70 decided) |
The exact values behind both chart views, one row per analyzer and snapshot.
Kernels at a glance
One bar per analyzer, one panel per kernel. Each bar is that analyzer's own
core population, split into decisive-correct, decisive-wrong,
incomplete, and declined. The incomplete segment combines
inconclusive proof and runner-error executions, which the panel labels count
separately; declined means unsupported only. The segments ensure
the remainder of a bar is never read as a wrong answer.
Panels are separate populations with separate denominators: compare bars
inside a panel, never across panels, and never against the modeling
or tool-native sections above. Every kernel here is on the
benchmark-controlled model profile.
None of the 51 analyzer rows published across these 14 kernels answers its whole core correctly, and 18 of them answer every assertion in their kernel definitively — with no inconclusive results, unsupported outcomes, or runner errors. The template-by-template outcome for every one of these rows — each balanced positive/negative pair, per analyzer — is on the semantic templates page, with per-case classifications and retained raw evidence on the case evidence page.
Direct-flow breadth across languages
The breadth baseline is one balanced direct-propagation pair per
language, on Bifrost's all-language smoke run: a separate, much smaller
population from the kernels above, and never pooled with them. Each chip is
one language, with a mark for the positive and the negative assertion.
-
c -
cpp -
csharp -
go -
java -
javascript -
kotlin -
php -
python -
ruby -
rust -
scala -
typescript
Bifrost answers both assertions correctly in
13 of 13 languages. The exact
reached / not-reached outcome for each of those
assertions is on the
semantic templates page, under the
smoke scorecard's direct-propagation rows.
Why these numbers are trustworthy
Every count on this page is generated from the
freeze
manifest (750e3b8c1275…),
which digest-binds the benchmark revision, every case and fixture, every
analyzer's identity, their normalized reports, and one retained raw
artifact per result. CI regenerates the numbers from the manifest and fails
on any drift; hand-authored prose cannot override a generated count. See
reproduction to verify locally,
or dive into the full
snapshot —
analyzers,
languages,
templates,
and per-case
evidence.