CodeChecker是基于LLVM/Clang Static Analyzer工具链的一个静态分析框架,替代了linux或者mac里的scan-build。

github仓库:https://github.com/Ericsson/codechecker

文档:https://codechecker.readthedocs.io/en/latest/

简介

CodeChecker在github仓库有1.6k的star。文档也提出这是一个框架,意味着它可以整合很多的静态工具,包括cppcheck和infer等等,还有java,python的静态分析器。本文主要用的是clang-tidy和clang static analyzer这两个。

安装

pip3 install codechecker

要直接在命令行使用的话,需要设置下环境变量。

使用

CodeChecker的步骤可以分为三步:

  • log:运行程序的build命令,记录编译的过程。这些过程会被导出为json格式。
  • analyze:基于前面的json文件来对程序进行分析,并输出结果。
  • postprocess:对结果做处理
  • parse:解析分析的结果,输出好看的summary和结果。
  • store:存储结果到正在运行的codechecker 服务器
  • cmd diff:比较两个分析结果,并展示差别
  • etc …

step1:log

现在结合一个实例来用用看codechecker。还是用libpng来试试。

首先,清理掉之前编译的结果。

make clean

然后使用codechecker 记录build 命令

./configure --disable-shared
CodeChecker log --build "make" --output ./compile_commands.json

运行完该命令后,可以看看这个json文件都是啥玩意。从下图可以很明显知道,这个log的过程实际上就是确定要分析哪些源代码文件。

check for all the rules代码 code crack_静态分析

step2:analyze

接着,就可以开始下一步分析了。输入如下命令即可开始分析。

CodeChecker analyze ./compile_commands.json --enable sensitive --output ./reports

enable sensitive以实是开启了部分的checker,也就是能够检测某些漏洞。如果想看更多的checker,可以输入下面的命令

# 列举所有可用的checker
CodeChecker checkers --help
# 显示checker的具体信息
CodeChecker checkers --detail
# 显示checker的组,比如前面指的sensitive
CodeChecker checkers --profile --details
# 显示属于sensitive 的checker
CodeChecker checkers --profile sensitive --details

可以看到终端输出如下信息:

[INFO 2022-08-09 06:06] - Enabled checkers:
clang-tidy: boost-use-to-string, bugprone-argument-comment, bugprone-assert-side-effect, bugprone-bad-signal-to-kill-thread, bugprone-bool-pointer-implicit-conversion, bugprone-branch-clone, bugprone-copy-constructor-init, bugprone-dangling-handle, bugprone-dynamic-static-initializers, bugprone-exception-escape, bugprone-fold-init-type, bugprone-forward-declaration-namespace, bugprone-forwarding-reference-overload, bugprone-inaccurate-erase, bugprone-incorrect-roundings, bugprone-infinite-loop, bugprone-integer-division, bugprone-lambda-function-name, bugprone-macro-parentheses, bugprone-macro-repeated-side-effects, bugprone-misplaced-operator-in-strlen-in-alloc, bugprone-misplaced-pointer-arithmetic-in-alloc, bugprone-misplaced-widening-cast, bugprone-move-forwarding-reference, bugprone-multiple-statement-macro, bugprone-narrowing-conversions, bugprone-no-escape, bugprone-not-null-terminated-result, bugprone-parent-virtual-call, bugprone-posix-return, bugprone-redundant-branch-condition, bugprone-reserved-identifier, bugprone-signal-handler, bugprone-signed-char-misuse, bugprone-sizeof-container, bugprone-sizeof-expression, bugprone-spuriously-wake-up-functions, bugprone-string-constructor, bugprone-string-integer-assignment, bugprone-string-literal-with-embedded-nul, bugprone-suspicious-enum-usage, bugprone-suspicious-include, bugprone-suspicious-memset-usage, bugprone-suspicious-missing-comma, bugprone-suspicious-semicolon, bugprone-suspicious-string-compare, bugprone-swapped-arguments, bugprone-terminating-continue, bugprone-throw-keyword-missing, bugprone-too-small-loop-variable, bugprone-undefined-memory-manipulation, bugprone-undelegated-constructor, bugprone-unhandled-self-assignment, bugprone-unused-raii, bugprone-unused-return-value, bugprone-use-after-move, bugprone-virtual-near-miss, cert-con36-c, cert-con54-cpp, cert-dcl03-c, cert-dcl16-c, cert-dcl21-cpp, cert-dcl37-c, cert-dcl50-cpp, cert-dcl51-cpp, cert-dcl54-cpp, cert-dcl58-cpp, cert-dcl59-cpp, cert-env33-c, cert-err09-cpp, cert-err34-c, cert-err52-cpp, cert-err58-cpp, cert-err60-cpp, cert-err61-cpp, cert-fio38-c, cert-flp30-c, cert-mem57-cpp, cert-msc30-c, cert-msc32-c, cert-msc50-cpp, cert-msc51-cpp, cert-oop11-cpp, cert-oop54-cpp, cert-oop57-cpp, cert-oop58-cpp, cert-pos44-c, cert-sig30-c, cert-str34-c, cppcoreguidelines-pro-type-const-cast, cppcoreguidelines-pro-type-static-cast-downcast, cppcoreguidelines-slicing, cppcoreguidelines-special-member-functions, google-build-explicit-make-pair, google-build-namespaces, google-build-using-namespace, google-explicit-constructor, google-global-names-in-headers, google-runtime-int, google-runtime-operator, misc-definitions-in-headers, misc-misplaced-const, misc-redundant-expression, misc-unconventional-assign-operator, misc-uniqueptr-reset-release, misc-unused-alias-decls, misc-unused-using-decls, modernize-deprecated-headers, modernize-replace-auto-ptr, modernize-replace-random-shuffle, mpi-buffer-deref, mpi-type-mismatch, performance-faster-string-find, performance-for-range-copy, performance-implicit-conversion-in-loop, performance-inefficient-algorithm, performance-inefficient-string-concatenation, performance-inefficient-vector-operation, performance-move-const-arg, performance-move-constructor-init, performance-no-automatic-move, performance-no-int-to-ptr, performance-noexcept-move-constructor, performance-trivially-destructible, performance-type-promotion-in-math-fn, performance-unnecessary-copy-initialization, performance-unnecessary-value-param
clangsa: alpha.core.BoolAssignment, alpha.core.CastSize, alpha.core.Conversion, alpha.core.DynamicTypeChecker, alpha.core.SizeofPtr, alpha.core.TestAfterDivZero, alpha.cplusplus.DeleteWithNonVirtualDtor, alpha.cplusplus.EnumCastOutOfRange, alpha.cplusplus.InvalidatedIterator, alpha.cplusplus.IteratorRange, alpha.cplusplus.MismatchedIterator, alpha.cplusplus.STLAlgorithmModeling, alpha.cplusplus.SmartPtr, alpha.security.MmapWriteExec, alpha.security.ReturnPtrRange, alpha.security.cert.pos.34c, alpha.security.taint.TaintPropagation, alpha.unix.BlockInCriticalSection, alpha.unix.Chroot, alpha.unix.PthreadLock, alpha.unix.Stream, alpha.unix.cstring.NotNullTerminated, alpha.unix.cstring.OutOfBounds, core.CallAndMessage, core.DivideZero, core.NonNullParamChecker, core.NullDereference, core.StackAddressEscape, core.UndefinedBinaryOperatorResult, core.VLASize, core.uninitialized.ArraySubscript, core.uninitialized.Assign, core.uninitialized.Branch, core.uninitialized.CapturedBlockVariable, core.uninitialized.UndefReturn, cplusplus.InnerPointer, cplusplus.Move, cplusplus.NewDelete, cplusplus.NewDeleteLeaks, cplusplus.PlacementNew, cplusplus.PureVirtualCall, deadcode.DeadStores, nullability.NullPassedToNonnull, nullability.NullReturnedFromNonnull, nullability.NullableDereferenced, nullability.NullablePassedToNonnull, nullability.NullableReturnedFromNonnull, optin.cplusplus.UninitializedObject, optin.cplusplus.VirtualCall, optin.mpi.MPI-Checker, optin.portability.UnixAPI, security.FloatLoopCounter, security.insecureAPI.UncheckedReturn, security.insecureAPI.getpw, security.insecureAPI.gets, security.insecureAPI.mkstemp, security.insecureAPI.mktemp, security.insecureAPI.rand, security.insecureAPI.vfork, unix.API, unix.Malloc, unix.MallocSizeof, unix.MismatchedDeallocator, unix.Vfork, unix.cstring.BadSizeArg, unix.cstring.NullArg, valist.CopyToSelf, valist.Uninitialized, valist.Unterminated
[INFO 2022-08-09 06:06] - Starting static analysis ...
[INFO 2022-08-09 06:06] - [1/60] clang-tidy analyzed pngrio.c successfully.

...
[INFO 2022-08-09 06:06] - [58/60] clangsa analyzed png.c successfully.
[WARNING 2022-08-09 06:06] - Previous analysis results in '/home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/reports/png.c_clangsa_434fc486b6e177fd54310eb11a3482b3.plist' has been overwritten.
[INFO 2022-08-09 06:06] - [59/60] clangsa analyzed pngfix.c successfully.
[WARNING 2022-08-09 06:06] - Previous analysis results in '/home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/reports/pngfix.c_clangsa_ba07ed53654a4d59ca58c53e53b2c2af.plist' has been overwritten.
[INFO 2022-08-09 06:06] - [60/60] clangsa analyzed pngrutil.c successfully.
[WARNING 2022-08-09 06:06] - Previous analysis results in '/home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/reports/pngrutil.c_clangsa_833aa45b93bfffdc4e1c822fc1cd1e66.plist' has been overwritten.
[INFO 2022-08-09 06:06] - ----==== Summary ====----
[INFO 2022-08-09 06:06] - Successfully analyzed
[INFO 2022-08-09 06:06] -   clang-tidy: 30
[INFO 2022-08-09 06:06] -   clangsa: 30
[INFO 2022-08-09 06:06] - Reanalyzed compilation commands: 30
[INFO 2022-08-09 06:06] - Total analyzed compilation commands: 30
[INFO 2022-08-09 06:06] - ----=================----
[INFO 2022-08-09 06:06] - Analysis finished.
[INFO 2022-08-09 06:06] - To view results in the terminal use the "CodeChecker parse" command.
[INFO 2022-08-09 06:06] - To store results use the "CodeChecker store" command.
[INFO 2022-08-09 06:06] - See --help and the user guide for further options about parsing and storing the reports.
[INFO 2022-08-09 06:06] - ----=================----
[INFO 2022-08-09 06:06] - Analysis length: 22.119323253631592 sec.

然后可以看到当前目录的report文件下有以下这些plist文件。

pngwtran.c_clang-tidy_b72547538acb76955b4cb5907edea56d.plist
pngwutil.c_clangsa_e7f13b748da8247ecb13767160fed60e.plist
pngwutil.c_clang-tidy_e7f13b748da8247ecb13767160fed60e.plist
powerpc_init.c_clangsa_0640f12de3b39e9beee8114e182365ed.plist
powerpc_init.c_clang-tidy_0640f12de3b39e9beee8114e182365ed.plist
timepng.c_clangsa_b7c3f136c01c6bbeb39bfdbc200c1576.plist
timepng.c_clang-tidy_b7c3f136c01c6bbeb39bfdbc200c1576.plist
...

这些plist文件的内容是xml文件,直接看可读性有点差。

看到这里,发现文档说可以把步骤1和步骤2合成为一个命令:

CodeChecker check --jobs 22 --build "make clean ; make --jobs 4" \
    --output ./reports --clean --enable sensitive

step3:后续处理

可以使用parse命令把它解析下

CodeChecker parse ./reports

可以看到如下的内容,包括每个报告的具体行号以及最后的summary。

[MEDIUM] /home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/png.h:586:38: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
#define PNG_TEXT_COMPRESSION_NONE_WR -3
                                     ^

[MEDIUM] /home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/png.h:587:38: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
#define PNG_TEXT_COMPRESSION_zTXt_WR -2
                                     ^

[MEDIUM] /home/iskindar/Project/StaticReportAnalyzer/testbench/libpng/repo/png.h:588:38: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
#define PNG_TEXT_COMPRESSION_NONE    -1
                                     ^
...
----==== Severity Statistics ====----
----------------------------
Severity | Number of reports
----------------------------
MEDIUM   |                63
LOW      |                55
HIGH     |                 5
----------------------------
----=================----

----==== Checker Statistics ====----
----------------------------------------------------------------
Checker name                      | Severity | Number of reports
----------------------------------------------------------------
bugprone-macro-parentheses        | MEDIUM   |                21
cert-err34-c                      | LOW      |                 5
bugprone-reserved-identifier      | LOW      |                12
cert-dcl37-c                      | LOW      |                12
cert-dcl51-cpp                    | LOW      |                12
alpha.security.ReturnPtrRange     | HIGH     |                 1
performance-no-int-to-ptr         | LOW      |                 3
bugprone-branch-clone             | LOW      |                 7
unix.Malloc                       | MEDIUM   |                 1
bugprone-narrowing-conversions    | MEDIUM   |                31
deadcode.DeadStores               | LOW      |                 4
bugprone-signed-char-misuse       | MEDIUM   |                 3
cert-str34-c                      | MEDIUM   |                 3
alpha.unix.Stream                 | MEDIUM   |                 3
core.NullDereference              | HIGH     |                 1
cert-dcl03-c                      | MEDIUM   |                 1
bugprone-suspicious-missing-comma | HIGH     |                 1
core.NonNullParamChecker          | HIGH     |                 2
----------------------------------------------------------------
----=================----

----==== File Statistics ====----
----------------------------------
File name      | Number of reports
----------------------------------
png.h          |                 5
pngget.c       |                 4
pngpriv.h      |                 8
pngtest.c      |                 3
powerpc_init.c |                 3
pngerror.c     |                 3
pngstest.c     |                 6
pngread.c      |                 1
pngrutil.c     |                 4
pngmem.c       |                 2
pngset.c       |                 8
png.c          |                11
mips_init.c    |                 3
pngimage.c     |                12
timepng.c      |                 3
pngfix.c       |                27
pngrtran.c     |                 1
pngpread.c     |                 1
pngvalid.c     |                15
pngcp.c        |                 3
----------------------------------
----=================----

----======== Summary ========----
-----------------------------------------------
Number of processed analyzer result files | 60 
Number of analyzer reports                | 123
-----------------------------------------------
----=================----

当然也可以解析为html

CodeChecker parse --export html --output ./reports_html ./reports

打开网页可以看到以下这些信息,还有路径的长度。

check for all the rules代码 code crack_sed_02

除了html外,也可以导出为json,codeclimate等格式

export arguments:
  -e {html,json,codeclimate,gerrit,baseline}, --export {html,json,codeclimate,gerrit,baseline}
                        Specify extra output format type.
                        'codeclimate' format can be used for Code Climate and for GitLab integration. For more
                        information see:
                        https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#data-types
                        'baseline' output can be used to integrate CodeChecker into your local workflow without using a
                        CodeChecker server. For more information see our usage guide. (default: None)

到此本文基本结束了,但codechecker还有很多有意思的内容没有介绍,就需要读者自己看文档琢磨了。(虽然文章的主要目的是记录,以防后面自己又要回过头来用这个工具)

其他有意思的内容暂且记录如下:

  • 自动修复:CodeChecker fixit ./reports
  • diff
  • 如何整合其他的静态工具