1. Overview
This site collects three related artifacts:
- CodeQL databases built from open-source projects.
- CodeQL analysis results for those projects.
The intended uses are:
- Provide ready-made databases for CodeQL query development.
- Provide large ready-made analysis result sets for work on presenting and disseminating results that may number in the millions.
- Provide databases for the MRVA project.
Future work includes summary pages that explain the workflow, data locations, and
comparisons of full tracing builds to --build-mode=none
The corpus is based on deployed open-source software rather than arbitrary
GitHub repositories. The databases were built from a random sample of 7000
Debian projects drawn from a much larger Debian package population. Of those
7000 projects, 2487 successfully produced a C/C++ CodeQL database using full
build tracing. Of those projects, 843 also successfully produced a C/C++
CodeQL database using --build-mode=none, where CodeQL reads the source tree
without tracing a build. No other languages are included yet.
This document follows the standard, but often under-explained, end-to-end CodeQL path:
- Convert source code into CodeQL database bundles. The database is the artifact that CodeQL queries examine.
- Apply query suites to one or more CodeQL databases. Each analyzed database produces one SARIF file containing zero or more results.
- Build reports and comparisons from the SARIF results.
The same path applies to one database and to large corpora, but the scale changes the engineering problem.
- Single database: choose one source tree, build one database, and run one query suite. If 20 queries produce results, the output is small enough for direct review and direct SARIF inspection.
- Corpus scale: choose 2487 source trees, build two databases per project
when comparing BMF and BMN, and run one query suite. If 20 queries produce
results per database, that is about
2487 * 2 * 20 = 99480result groups before considering multiple findings per query. Direct SARIF inspection is no longer practical; SQL ingestion becomes useful. - Large recurring scale: choose 120000 source trees, build one database per
project, and run one query suite weekly. If 20 queries produce results per
database, one run can produce about
120000 * 20 = 2400000result groups. Keeping recent weekly runs plus monthly snapshots quickly reaches tens of millions of result groups. At that point, a high-performance SQL engine such as DuckDB is required for comparison and reporting.
The following sections describe the general workflow used across the source repository corpus. For two concrete end-to-end examples, see the detailed QEMU and DPDK directories. They follow the same create/analyze workflow, with additional logging for CPU, RAM, disk use, package events, SQLite import, and gnuplot graph generation.
2. From code to CodeQL DB
Start with a source tree source. Create a CodeQL database
codeql_DB_type from source, where type is either full build tracing or
build-mode=none. The resulting database directory is zipped so it can be
analyzed later or moved between hosts.
The two database creation modes are:
bmf, build-mode full: CodeQL traces a real build withcodeql database create ... --command'…' …=. Successful database bundles are under data/codeql-db-zips-bm-full/.bmn, build-mode none: CodeQL scans visible C/C++ source without running the build withcodeql database create ... --build-mode=none .... Successful database bundles are under data/codeql-db-zips-bm-none/.
2.1. Results for Full Build Trace
This is labeled bmf, for build-mode full. CodeQL observes a real build, so
the database reflects files and compiler options that actually participated in
that build.
codeql database create DB_DIR \ --language=cpp \ --source-root=SOURCE_DIR \ --command='debian/rules build' \ --threads="$THREADS" \ --ram="$RAM_MB" codeql database bundle --output PROJECT.zip DB_DIR
The corpus-level BMF database bundles are available at data/codeql-db-zips-bm-full/; a paginated searchable listing follows. There are 2487 successful BMF DB zip bundles.
2.2. Results for build-mode=none
This is labeled bmn, for build-mode=none. CodeQL does not run the build; it
infers extraction from the source tree.
The core CodeQL command used to build every one of these DBs is
codeql database create \ --language=cpp \ --source-root="$SOURCE_ROOT" \ --threads="$THREADS" \ --ram="$RAM_MB" \ --build-mode=none \ "$DB_PATH"
The corpus-level BMN database bundles are available at data/codeql-db-zips-bm-none/; a paginated searchable listing follows. There are 843 successful BMN DB zip bundles.
3. From CodeQL DB to results
After database creation, DBs from both modes are analyzed with a CodeQL query suite; standard preinstalled query suites useful for C/C++ include:
cpp-security-and-quality.qls- broad security and quality suite used here.
cpp-security-extended.qls- security-focused suite with extended checks.
cpp-code-scanning.qls- default code-scanning-oriented suite.
- (no term)
- Individual query packs or query paths under the installed CodeQL checkout.
Here, CodeQL version 2.23.6 was used.
The analysis steps are identical for bmf and bmn; only the DB zip and
output SARIF directory change.
- Choose the DB zip.
- Extract it to a temporary directory.
- Find the directory containing
codeql-database.yml. - Run
codeql database analyzewith the selected suite. - Store the SARIF and retain stdout, stderr, resource logs, and status.
The core CodeQL command used to analyze every CodeQL DB is
codeql database analyze \ --format=sarif-latest \ --rerun \ -j"$THREADS" \ --ram="$RAM_MB" \ --output "$SARIF" \ -- "$DB_DIR" cpp-security-and-quality.qls
3.1. SARIF files produced for bm-full
The work here used the C/C++ cpp-security-and-quality suite. The BMF SARIF
outputs are available at
data/bmf-db-cpp-security-and-quality-sarifs/.
There are 2486 BMF C/C++ cpp-security-and-quality SARIF files.
3.2. SARIF files produced for bm-none
This section also used the C/C++ cpp-security-and-quality suite. The BMN SARIF
outputs are available at data/bmn-db-cpp-security-and-quality-sarifs/.
There are 832 BMN C/C++ cpp-security-and-quality SARIF files, significantly
fewer than the analysis of databases from full builds.
4. Comparing CodeQL database build options
There are two choices when building a C/C++ CodeQL database for this corpus.
A full build trace uses --command to observe a real build. A database
created with --build-mode=none examines source code without running the
build.
The SARIF file size comparison and the largest BMF/BMN SARIF size differences already suggest that the two database modes can produce substantially different analysis output. File size is only a proxy, though, so the more direct comparison is at the result level.
After converting SARIF results to a SQL database, using the result identity
file_name, kind, rule_id, rule_name, uri, start_line, start_column
gives the following counts of distinct result keys.
kind comparison result_count path-problem common 4,149 path-problem only_full 32,685 path-problem only_none 3,595 problem common 126,238 problem only_full 699,833 problem only_none 843,338
4.1. Interpretation
Across more than 2,400 CodeQL databases, the overlap between build-mode=none and a full build is only 10.3% for path-problem results and 7.6% for problem results. These differences are orders of magnitude larger than would be expected from random variation, indicating that the two build modes produce substantially different result sets.
For path-problem results:
| Comparison | Count |
|---|---|
| common | 4,149 |
| only_full | 32,685 |
| only_none | 3,595 |
Only about 10.3% of distinct path results are common:
4,149 / (4,149 + 32,685 + 3,595) ~= 10.3%
For problem results:
| Comparison | Count |
|---|---|
| common | 126,238 |
| only_full | 699,833 |
| only_none | 843,338 |
Only about 7.6% of distinct problem results are common:
126,238 / (126,238 + 699,833 + 843,338) ~= 7.6%
These values are low enough that the two modes should be treated as substantially different analyses, not as equivalent runs over the same effective program.
More specifically:
- For
path-problemresults, the full build produces many more unique results thanbuild-mode=none, but there is still a nontrivialonly_noneset. - For
problemresults,build-mode=noneproduces more unique results than the full build, but both modes have very large exclusive sets.
The surprising part is the small intersection. That suggests one or more of:
- database creation mode affects database contents substantially.
- result identity may be too location-sensitive.
- rule behavior changes because extracted code or dependencies differ.
- many alerts are sensitive to build configuration.
file_nameorurinormalization may differ between modes.
A useful summary metric is Jaccard similarity: ignoring which build mode is "correct," how much do the two analyses agree on the set of findings?
common / (common + only_none + only_full)
Current values:
| Kind | Jaccard similarity |
|---|---|
| path-problem | 0.103 |
| problem | 0.076 |
4.2. Treating tracing build as the reference
If the full build is treated as the best available approximation of the true
result set, then the build-mode=none results can be evaluated as an
approximation of that reference. Let
\[ T = F \]
be the reference ("truth"), and
\[ A = N \]
be the approximation produced by build-mode=none.
Then
\[ TP = |N \cap F| \]
\[ FP = |N \setminus F| \]
\[ FN = |F \setminus N| \]
4.2.1. Path problems
Given
\[ TP = 4149,\quad FP = 3595,\quad FN = 32685, \]
we obtain
\[ \text{Precision} = \frac{TP}{TP+FP} = \frac{4149}{4149+3595} \approx 0.536, \]
and
\[ \text{Recall} = \frac{TP}{TP+FN} = \frac{4149}{4149+32685} \approx 0.113. \]
Thus, build-mode=none reproduces only about 11.3% of the path problems
reported by the full build.
4.2.2. Problems
Given
\[ TP = 126238,\quad FP = 843338,\quad FN = 699833, \]
we obtain
\[ \text{Precision} = \frac{126238}{126238+843338} \approx 0.130, \]
and
\[ \text{Recall} = \frac{126238}{126238+699833} \approx 0.153. \]
Thus, build-mode=none reproduces only about 15.3% of the problem results
reported by the full build.
4.2.3. Summary
| Kind | Precision | Recall |
|---|---|---|
| path-problem | 53.6% | 11.3% |
| problem | 13.0% | 15.3% |
Overall, if the full build is taken as the best approximation of the true
result set, then build-mode=none is a poor approximation.
For path-problem, it achieves moderate precision but very low recall: when it
agrees with the full build it is often correct, but it misses nearly nine out
of ten findings.
For problem results, both precision and recall are low, indicating that the
two analyses report substantially different sets of findings.
5. Appendix
5.1. Precision and recall
Precision and recall are asymmetric measures: one result set is chosen as the reference ("truth"), and the other is evaluated against it.
For this discussion, let
\[ T = F \]
denote the results obtained from the full build, which we treat as the best available approximation of the true result set. Let
\[ A = N \]
denote the results obtained from --build-mode=none.
The results naturally partition into three disjoint sets:
\[ TP = A \cap T, \]
the results reported by both analyses (true positives),
\[ FP = A \setminus T, \]
the results reported only by --build-mode=none (false positives with respect to
the reference), and
\[ FN = T \setminus A, \]
the results reported only by the full build (false negatives).
5.1.1. Precision
Precision answers the question:
Of the results reported by
--build-mode=none, what fraction also appear in the reference analysis?
It is defined as
\[ \operatorname{Precision} = \frac{TP}{TP+FP}. \]
A precision of 1.0 means every reported result also appears in the reference.
A low precision indicates that many results are unique to
--build-mode=none.
In this study, a result counted as a false positive is not necessarily incorrect; it simply does not appear in the full build. Without knowing the true set of defects, we cannot determine whether these findings are genuine or spurious.
5.1.2. Recall
Recall answers the complementary question:
Of the results reported by the reference analysis, what fraction were also found by
--build-mode=none?
It is defined as
\[ \operatorname{Recall} = \frac{TP}{TP+FN}. \]
A recall of 1.0 means that --build-mode=none reproduced every finding from the
full build. A low recall indicates that many findings from the full build are
missing.
Again, because the full build is only an approximation of the true result set,
these "false negatives" are simply findings absent from --build-mode=none, not
necessarily true defects that were missed.
5.1.3. Interpretation
Precision and recall measure different properties.
- High precision, low recall:
--build-mode=nonereports relatively few unique findings, but misses many of those reported by the full build. - Low precision, high recall:
--build-mode=nonefinds most results from the full build, but also reports many additional findings. - High precision, high recall: The two analyses produce very similar result sets.
In this work, the distinction is important because neither build mode is known
to produce the true set of defects. The full build is used solely as a
reference, allowing us to quantify how closely --build-mode=none reproduces its
results.