In the same vein as copyright_header.py (#9459) and basic_style.py (#9603), this script provides a consistent way to run clang static analysis checking on the codebase.
$ contrib/devtools/clang_static_analysis.py -h
usage: clang_static_analysis.py [-h] [-b BIN_PATH] [-r REPORT_PATH] [-j JOBS]
{report,check} repository
A utility for running clang static analysis on the codebase in a consistent
way.
positional arguments:
{report,check} Selects the output behavior. 'report' generates a
summary report on the issues found. 'check' compares
the state of the repository against a standard,
provides a return code for the shell and prints more
specific details when issues are found.
repository A source code repository for which the static analysis
is to be performed upon.
optional arguments:
-h, --help show this help message and exit
-b BIN_PATH, --bin-path BIN_PATH
The path holding 'scan-build' and 'scan-view'
binaries. (Uses 'scan-build' and 'scan-view' installed
in PATH by default)
-r REPORT_PATH, --report-path REPORT_PATH
The path for scan-build to write its report files.
(default=/tmp/bitcoin-scan-build/)
-j JOBS, --jobs JOBS The number of parallel jobs to run with 'make'.
(default=6)
The report subcommand is for providing a summary of the state of the checked-out branch. On current master, the output looks like this:
$ contrib/devtools/clang_static_analysis.py report .
Running command: make clean
Running command: /usr/share/clang/scan-build-3.5/scan-build -k -plist-html --keep-empty -o /tmp/bitcoin-scan-build/ make -j6
stderr/stdout to: scan_build.log
This might take a few minutes...
Done.
Results in: /tmp/bitcoin-scan-build/2017-01-25-140103-6556-1
--------------------------------------------------------------------------------
Took 143.30 seconds to analyze with scan-build
Found 3 issues:
--------------------------------------------------------------------------------
0: bench/bench.cpp:97:52 - Division by zero
1: qt/paymentrequest.pb.cc:51:24 - Called C++ object pointer is null
2: ./src/ecmult_gen_impl.h:153:5 - Value stored to 'bits' is never read
--------------------------------------------------------------------------------
Full details can be seen in a browser by running:
$ /usr/share/clang/scan-view-3.5/scan-view /tmp/bitcoin-scan-build/2017-01-25-140103-6556-1
--------------------------------------------------------------------------------
The results directory is kept around in the /tmp/ location and scan-view gives you a full, very nice visualization of the results in your browser.
The check subcommand provides a bit more specific detail and returns a shell status of zero only if there aren't any issues. Like with the other scripts, this is useful for eventual inclusion as a criteria for CI acceptance. Its output looks like this:
$ contrib/devtools/clang_static_analysis.py check .
Running command: make clean
Running command: /usr/share/clang/scan-build-3.5/scan-build -k -plist-html --keep-empty -o /tmp/bitcoin-scan-build/ make -j6
stderr/stdout to: scan_build.log
This might take a few minutes...
Done.
Results in: /tmp/bitcoin-scan-build/2017-01-25-140349-11169-1
--------------------------------------------------------------------------------
An issue has been found in bench/bench.cpp:97:52
Type: Division by zero
Description: Division by zero
0: bench/bench.cpp:93:5 - The value 0 is assigned to field 'count'
1: bench/bench.cpp:97:52 - Division by zero
--------------------------------------------------------------------------------
An issue has been found in ./src/ecmult_gen_impl.h:153:5
Type: Dead assignment
Description: Value stored to 'bits' is never read
0: ./src/ecmult_gen_impl.h:153:5 - Value stored to 'bits' is never read
--------------------------------------------------------------------------------
An issue has been found in qt/paymentrequest.pb.cc:51:24
Type: Called C++ object pointer is null
Description: Called C++ object pointer is null
0: qt/paymentrequest.pb.cc:47:3 - 'file' initialized here
1: qt/paymentrequest.pb.cc:50:3 - Assuming pointer value is null
2: qt/paymentrequest.pb.cc:51:24 - Called C++ object pointer is null
--------------------------------------------------------------------------------
Full details can be seen in a browser by running:
$ /usr/share/clang/scan-view-3.5/scan-view /tmp/bitcoin-scan-build/2017-01-25-140349-11169-1
--------------------------------------------------------------------------------
*** Static analysis issues found!
Tthe first issue is fixed by PR #9547, the second looks like a trivial fix in secp256k1, and the third is a clear false-positive that is fixed in clang versions 3.9.0+. This output is from a run with clang 3.5.0 and all versions I tried (all of 3.4.0 through 3.9.1) return the same two real issues and no additional false-positives.
There are additional, stricter plugins for clang's checking but this script doesn't invoke them. It is sticking to only the defaults for now. Presumably false-positives become more frequent as the strictness increases. Seeing as there doesn't appear to be anything too strange at this baseline level of checking, eventual inclusion in CI appears to be a viable idea.
<sub>(screenshot may not reflect reality)