From 077d498c14374e407cd491be89af062bea1063b7 Mon Sep 17 00:00:00 2001 From: Thom Troy Date: Mon, 3 Jul 2017 22:39:51 +0100 Subject: [PATCH] add clang static analysis --- 04-static-analysis/README.adoc | 1 + .../clang-analyzer/CMakeLists.txt | 13 ++ 04-static-analysis/clang-analyzer/README.adoc | 154 ++++++++++++++++++ 04-static-analysis/clang-analyzer/run_test.sh | 5 + .../clang-analyzer/subproject1/CMakeLists.txt | 10 ++ .../clang-analyzer/subproject1/main1.cpp | 7 + .../clang-analyzer/subproject2/CMakeLists.txt | 10 ++ .../clang-analyzer/subproject2/main2.cpp | 9 + test.sh | 3 +- 9 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 04-static-analysis/clang-analyzer/CMakeLists.txt create mode 100644 04-static-analysis/clang-analyzer/README.adoc create mode 100755 04-static-analysis/clang-analyzer/run_test.sh create mode 100644 04-static-analysis/clang-analyzer/subproject1/CMakeLists.txt create mode 100644 04-static-analysis/clang-analyzer/subproject1/main1.cpp create mode 100644 04-static-analysis/clang-analyzer/subproject2/CMakeLists.txt create mode 100644 04-static-analysis/clang-analyzer/subproject2/main2.cpp diff --git a/04-static-analysis/README.adoc b/04-static-analysis/README.adoc index e38c15f..9cb8900 100644 --- a/04-static-analysis/README.adoc +++ b/04-static-analysis/README.adoc @@ -24,3 +24,4 @@ analysis tool. However standalone tools also exist. The examples here include using the following tools: * http://cppcheck.sourceforge.net/[CppCheck] +* https://clang-analyzer.llvm.org/[Clang Static Analyzer] diff --git a/04-static-analysis/clang-analyzer/CMakeLists.txt b/04-static-analysis/clang-analyzer/CMakeLists.txt new file mode 100644 index 0000000..e953049 --- /dev/null +++ b/04-static-analysis/clang-analyzer/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 3.0) + +project(cppcheck_analysis) + +# Use debug build as recommended +set(CMAKE_BUILD_TYPE Debug) + +# Have cmake create a compile database +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Add sub directories +add_subdirectory(subproject1) +add_subdirectory(subproject2) diff --git a/04-static-analysis/clang-analyzer/README.adoc b/04-static-analysis/clang-analyzer/README.adoc new file mode 100644 index 0000000..8059696 --- /dev/null +++ b/04-static-analysis/clang-analyzer/README.adoc @@ -0,0 +1,154 @@ += CppCheck Static Analysis using Compile Commands +:toc: +:toc-placement!: + +toc::[] + +# Introduction + +This example shows how to call the +https://clang-analyzer.llvm.org/[Clang Static Analyzer] to do static analysis using the +scan-build tool. + +The files included in this example are: + +``` +$ tree +. +├── CMakeLists.txt +├── subproject1 +│   ├── CMakeLists.txt +│   └── main1.cpp +└── subproject2 + ├── CMakeLists.txt + └── main2.cpp +``` + + * link:CMakeLists.txt[] - Top level CMakeLists.txt + * link:subproject1/CMakeLists.txt[] - CMake commands for subproject 1 + * link:subproject1/main.cpp[] - source for a subproject with no errors + * link:subproject2/CMakeLists.txt[] - CMake commands for subproject 2 + * link:subproject2/main2.cpp[] - source for a subproject that includes errors + +# Requirements + +To run this example you must have clang analyzer and the scan-build tool installed. This can be installed on Ubuntu using the following command. + +[source,bash] +---- +$ sudo apt-get install clang +---- + +It will result in the tool being available as: + +[source,bash] +---- +$ scan-build-3.6 +---- + +# Concepts + +## scan-build + +To run clang static analyzer you can use the tool `scan-build` to run the analyzer when you +also run the compiler. This overrides the CC and CXX environment variables and replaces them with it's own tools. To run it you can do + +[source,bash] +---- +$ scan-build-3.6 cmake .. +$ scan-build-3.6 make +---- + +By default this will run the standard compiler for your platform, i.e. `gcc` on linux. However, if you want to override this you can change the command to: + +[source,bash] +---- +$ scan-build-3.6 --use-cc=clang-3.6 --use-c++=clang++-3.6 -o ./scanbuildout/ make +---- + +## scan-build output + +scan-build will only output warnings during compile time and will also generate a list of HTML files which contain detailed analysis of the error. + +[source,bash] +---- +$ cd scanbuildout/ +$ tree +. +└── 2017-07-03-213514-3653-1 + ├── index.html + ├── report-42eba1.html + ├── scanview.css + └── sorttable.js + +1 directory, 4 files +---- + +By defaut these are output to +/tmp/scanbuildout/{run folder}+. You can change this using `scan-build -o /output/folder`. + +# Building the example + +[source,bash] +---- +$ mkdir build + +$ cd build/ + +$ scan-build-3.6 -o ./scanbuildout make +scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis +make: *** No targets specified and no makefile found. Stop. +scan-build: Removing directory '/data/code/clang-analyzer/build/scanbuildout/2017-07-03-211632-937-1' because it contains no reports. +scan-build: No bugs found. +devuser@91457fbfa423:/data/code/clang-analyzer/build$ scan-build-3.6 -o ./scanbuildout cmake .. +scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis +-- The C compiler identification is GNU 5.4.0 +-- The CXX compiler identification is GNU 5.4.0 +-- Check for working C compiler: /usr/share/clang/scan-build-3.6/ccc-analyzer +-- Check for working C compiler: /usr/share/clang/scan-build-3.6/ccc-analyzer -- works +-- Detecting C compiler ABI info +-- Detecting C compiler ABI info - done +-- Detecting C compile features +-- Detecting C compile features - done +-- Check for working CXX compiler: /usr/share/clang/scan-build-3.6/c++-analyzer +-- Check for working CXX compiler: /usr/share/clang/scan-build-3.6/c++-analyzer -- works +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Detecting CXX compile features +-- Detecting CXX compile features - done +-- Found CPPCHECK: /usr/local/bin/cppcheck +cppcheck found. Use cppccheck-analysis targets to run it +-- Configuring done +-- Generating done +-- Build files have been written to: /data/code/clang-analyzer/build +scan-build: Removing directory '/data/code/clang-analyzer/build/scanbuildout/2017-07-03-211641-941-1' because it contains no reports. +scan-build: No bugs found. + +$ $ scan-build-3.6 -o ./scanbuildout make +scan-build: Using '/usr/lib/llvm-3.6/bin/clang' for static analysis +Scanning dependencies of target subproject1 +[ 25%] Building CXX object subproject1/CMakeFiles/subproject1.dir/main1.cpp.o +[ 50%] Linking CXX executable subproject1 +[ 50%] Built target subproject1 +Scanning dependencies of target subproject2 +[ 75%] Building CXX object subproject2/CMakeFiles/subproject2.dir/main2.cpp.o +/data/code/clang-analyzer/subproject2/main2.cpp:7:17: warning: Dereference of null pointer (loaded from variable 'x') + std::cout << *x << std::endl; + ^~ +1 warning generated. +[100%] Linking CXX executable subproject2 +[100%] Built target subproject2 +scan-build: 1 bug found. +scan-build: Run 'scan-view /data/code/clang-analyzer/build/scanbuildout/2017-07-03-211647-1172-1' to examine bug reports. + +$ cd scanbuildout/ +$ tree +. +└── 2017-07-03-213514-3653-1 + ├── index.html + ├── report-42eba1.html + ├── scanview.css + └── sorttable.js + +1 directory, 4 files +---- + diff --git a/04-static-analysis/clang-analyzer/run_test.sh b/04-static-analysis/clang-analyzer/run_test.sh new file mode 100755 index 0000000..3d97c27 --- /dev/null +++ b/04-static-analysis/clang-analyzer/run_test.sh @@ -0,0 +1,5 @@ +#!/bin/bash +mkdir -p build \ + && cd build \ + && scan-build-3.6 -o scanbuildout cmake .. \ + && scan-build-3.6 -o scanbuildout make diff --git a/04-static-analysis/clang-analyzer/subproject1/CMakeLists.txt b/04-static-analysis/clang-analyzer/subproject1/CMakeLists.txt new file mode 100644 index 0000000..2554853 --- /dev/null +++ b/04-static-analysis/clang-analyzer/subproject1/CMakeLists.txt @@ -0,0 +1,10 @@ +# Set the project name +project (subproject1) + +# Create a sources variable with a link to all cpp files to compile +set(SOURCES + main1.cpp +) + +# Add an executable with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) diff --git a/04-static-analysis/clang-analyzer/subproject1/main1.cpp b/04-static-analysis/clang-analyzer/subproject1/main1.cpp new file mode 100644 index 0000000..98cacb2 --- /dev/null +++ b/04-static-analysis/clang-analyzer/subproject1/main1.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char *argv[]) +{ + std::cout << "Hello Main1!" << std::endl; + return 0; +} \ No newline at end of file diff --git a/04-static-analysis/clang-analyzer/subproject2/CMakeLists.txt b/04-static-analysis/clang-analyzer/subproject2/CMakeLists.txt new file mode 100644 index 0000000..bb05ae3 --- /dev/null +++ b/04-static-analysis/clang-analyzer/subproject2/CMakeLists.txt @@ -0,0 +1,10 @@ +# Set the project name +project (subproject2) + +# Create a sources variable with a link to all cpp files to compile +set(SOURCES + main2.cpp +) + +# Add an executable with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) diff --git a/04-static-analysis/clang-analyzer/subproject2/main2.cpp b/04-static-analysis/clang-analyzer/subproject2/main2.cpp new file mode 100644 index 0000000..de94989 --- /dev/null +++ b/04-static-analysis/clang-analyzer/subproject2/main2.cpp @@ -0,0 +1,9 @@ +#include + +int main(int argc, char *argv[]) +{ + std::cout << "Hello Main2!" << std::endl; + int* x = NULL; + std::cout << *x << std::endl; + return 0; +} diff --git a/test.sh b/test.sh index 48ef58a..9449a37 100755 --- a/test.sh +++ b/test.sh @@ -29,7 +29,8 @@ dirs=(./01-basic/A-hello-cmake \ ./03-code-generation/protobuf \ ./03-code-generation/configure-files \ ./04-static-analysis/cppcheck \ -./04-static-analysis/cppcheck \ +./04-static-analysis/cppcheck-compile-commands \ +./04-static-analysis/clang-analyzer \ ./05-unit-testing/boost \ ./06-installer/deb \ )