1#!/bin/bash 2 3# Copyright 2016 The Fuchsia Authors 4# 5# Use of this source code is governed by a MIT-style 6# license that can be found in the LICENSE file or at 7# https://opensource.org/licenses/MIT 8 9# This script will perform static analyses provided by Clang Static analyzers 10# on Zircon. It requires either a prebuilt Clang toolchan or a Clang toolchain 11# built from official Clang repository. For instructions on how to obtain a 12# prebuilt toolchain or build the toolchain from scratch, please refer to 13# document at 14# https://fuchsia.googlesource.com/zircon/+/master/docs/getting_started.md 15 16set -eu 17 18ORIGINAL_CWD="$(pwd)" 19 20# These are the default checkers for clang and are always on by defualt, 21# unless they are explicitley disabled 22CHECKERS_DEFAULT_ON="\ 23 apiModeling.google.GTest \ 24 core.CallAndMessage \ 25 core.DynamicTypePropagation \ 26 core.DivideZero \ 27 core.NonNullParamChecker \ 28 core.NullDereference \ 29 core.StackAddressEscape \ 30 core.UndefinedBinaryOperatorResult \ 31 core.VLASize \ 32 core.uninitialized.ArraySubscript \ 33 core.uninitialized.Assign \ 34 core.uninitialized.Branch \ 35 core.uninitialized.CapturedBlockVariable \ 36 core.uninitialized.UndefReturn \ 37 cplusplus.NewDelete \ 38 cplusplus.NewDeleteLeaks \ 39 cplusplus.SelfAssignment \ 40 deadcode.DeadStores \ 41 nullability.NullPassedToNonnull \ 42 nullability.NullReturnedFromNonnull \ 43 security.insecureAPI.UncheckedReturn \ 44 security.insecureAPI.getpw \ 45 security.insecureAPI.gets \ 46 security.insecureAPI.mkstemp \ 47 security.insecureAPI.mktemp \ 48 security.insecureAPI.vfork \ 49 unix.API \ 50 unix.Malloc \ 51 unix.MallocSizeof \ 52 unix.MismatchedDeallocator \ 53 unix.Vfork \ 54 unix.cstring.BadSizeArg \ 55 unix.cstring.NullArg \ 56" 57 58# Zircon specific checkers 59# Content may change in the future 60# TODO: This checker will only work after https://reviews.llvm.org/D36024 lands. 61CHECKERS_ZIRCON="alpha.zircon.ZirconHandleChecker" 62 63# Checkers that should be enabled 64CHECKERS_TO_ENABLE="" 65 66# Checkers that should be disabled 67CHECKERS_TO_DISABLE="" 68 69# Checkers Args that should be passed to Clang Static Analyzer 70CHECKERS="" 71 72func_disable_checkers() { 73 # Disable default checkers 74 for i in $CHECKERS_TO_DISABLE; do 75 CHECKERS="$CHECKERS -disable-checker $i" 76 done 77} 78 79func_enable_checkers() { 80 # Enable the checkers stored in $CHECKERS_TO_ENABLE 81 for i in $CHECKERS_TO_ENABLE; do 82 CHECKERS="$CHECKERS -enable-checker $i" 83 done 84} 85 86func_test_exist() { 87 if [ ! -e "$1" ]; then 88 echo "$1 does not exist! Please check your input. Aborting!" 89 exit -1 90 fi 91} 92 93func_trap_handler() { 94 cd "$ORIGINAL_CWD" 95 exit -1 96} 97 98# Register trap 99trap func_trap_handler SIGHUP SIGINT SIGTERM EXIT 100 101# Analyzer run mode. clang|zircon|all 102RUN_MODE="clang" 103# Path to python version of scan_build 104SCAN_BUILD_PY="" 105# Path to CC wrapper of scan_build_py 106SCAN_BUILD_PY_CC="" 107# Path to CXX wrapper of scan_build_py 108SCAN_BUILD_PY_CXX="" 109# Build target 110BUILD_TARGET="" 111 112# Path to clang 113CLANG_PATH="" 114 115# Path to clang++ 116CLANGXX_PATH="" 117 118# Path to toolchain 119TOOLCHAIN_PREFIX="" 120 121# Path to directory that contains scan-build-py/bin 122SCAN_BUILD_PY_PREFIX="" 123 124# Do not process unit tests flag 125DISABLE_UTEST=false 126 127function func_help { 128 echo "help:" 129 echo "-p <toolchain prefix> : path to the directory containing bin/clang" 130 echo "-s <scan-build-py prefix> : path to the directory bin/scan-build" 131 echo "-o <output dir> : path to output dir (default: AnalysisResult)" 132 echo "-m <clang|zircon|all> : run mode. clang mode will only enable checkers that" 133 echo " is enabled by default. zircon mode will only enable" 134 echo " zircon related checkers. all mode will enable both" 135 echo " default checkers and zircon related checkers." 136 echo " Default value is clang." 137 echo "-t <target> : build target. Default is x86" 138 echo "-n : do not run analyzer on unit tests" 139 echo "-h : for help" 140 exit 1 141} 142 143SOURCE="${BASH_SOURCE[0]}" 144while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink 145 SCRIPT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 146 SOURCE="$(readlink "$SOURCE")" 147 # if $SOURCE was a relative symlink, we need to resolve it relative to the 148 # path where the symlink file was located 149 [[ "$SOURCE" != /* ]] && SOURCE="$SCRIPT_DIR/$SOURCE" 150done 151SCRIPT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" 152ZIRCON_ROOT="$SCRIPT_DIR/.." 153 154# Path to output analysis results 155OUT_DIR="$ZIRCON_ROOT/AnalysisResult" 156 157# Read args from command line 158while getopts "p:s:t:o:m:hn" opt; do 159 case $opt in 160 p) TOOLCHAIN_PREFIX="$OPTARG";; 161 s) SCAN_BUILD_PY_PREFIX="$OPTARG";; 162 t) BUILD_TARGET="$OPTARG";; 163 o) OUT_DIR="$OPTARG";; 164 m) RUN_MODE="${OPTARG,,}";; 165 h) func_help;; 166 n) DISABLE_UTEST=true;; 167 \?) 168 echo "Inavlid option" 169 func_help 170 esac 171done 172 173# Determine the clang prefix 174if [ -z "$TOOLCHAIN_PREFIX" ]; then 175 # User did not provide toolchain prefix 176 # Assume user prefer prebuilt toolchain 177 PREBUILT_DIR="$ZIRCON_ROOT/prebuilt/downloads" 178 # Determine OS type 179 OS_STR="$(uname)" 180 if [ "$OS_STR" = "Darwin" ]; then 181 PREBUILT_DIR="$PREBUILT_DIR/clang+llvm-x86_64-darwin" 182 elif [ "$OS_STR" = "Linux" ]; then 183 PREBUILT_DIR="$PREBUILT_DIR/clang+llvm-x86_64-linux" 184 fi 185 if [ ! -d "$PREBUILT_DIR" ]; then 186 echo "Toolchain prefix is not defined and prebuilt toolchain has not yet been downloaded." 187 echo "Abort!" 188 exit -1 189 fi 190 TOOLCHAIN_PREFIX="$PREBUILT_DIR" 191fi 192 193CLANG_PATH="$TOOLCHAIN_PREFIX/bin/clang" 194CLANGXX_PATH="$TOOLCHAIN_PREFIX/bin/clang++" 195 196# Check if clang exists 197func_test_exist "$CLANG_PATH" 198func_test_exist "$CLANGXX_PATH" 199 200# Looking for scan-build-py 201# Prebuild does not have scan-build-py 202if [ -z "$SCAN_BUILD_PY_PREFIX" ]; then 203 # SCAN_BUILD_PY_PREFIX not defined 204 # Try fuchsia/third_party 205 SCAN_BUILD_PY_PREFIX="$ZIRCON_ROOT/../third_party/llvm/tools/clang/tools/scan-build-py" 206fi 207 208if [ ! -d "$SCAN_BUILD_PY_PREFIX" ]; then 209 echo "scan-build-py is not found at $SCAN_BUILD_PY_PREFIX, Aborting!" 210 exit -1 211fi 212 213SCAN_BUILD_PY="$SCAN_BUILD_PY_PREFIX/bin/scan-build" 214SCAN_BUILD_PY_CC="$SCAN_BUILD_PY_PREFIX/bin/analyze-cc" 215SCAN_BUILD_PY_CXX="$SCAN_BUILD_PY_PREFIX/bin/analyze-c++" 216 217# Test if scan-build exists 218func_test_exist "$SCAN_BUILD_PY" 219func_test_exist "$SCAN_BUILD_PY_CC" 220func_test_exist "$SCAN_BUILD_PY_CXX" 221 222# Construct Checker Args that should be passed to scan-build 223if [ "$RUN_MODE" = "zircon" ]; then 224 CHECKERS_TO_DISABLE="${CHECKERS_TO_DISABLE} ${CHECKERS_DEFAULT_ON}" 225 CHECKERS_TO_ENABLE="${CHECKERS_TO_ENABLE} ${CHECKERS_ZIRCON}" 226elif [ "$RUN_MODE" = "all" ]; then 227 CHECKERS_TO_ENABLE="${CHECKERS_TO_ENABLE} ${CHECKERS_ZIRCON}" 228fi 229func_disable_checkers 230func_enable_checkers 231 232# All clear, perform analysis 233# Change dir to zircon 234cd "$ZIRCON_ROOT" 235# Run scan-build on make 236if [ ! -z "${BUILD_TARGET}" ]; then 237 make USE_CLANG=true "${BUILD_TARGET}" clean &> /dev/null 238else 239 make USE_CLANG=true clean &> /dev/null 240fi 241 242CMDL="${SCAN_BUILD_PY}" 243CMDL="${CMDL} --use-cc ${CLANG_PATH}" 244CMDL="${CMDL} --use-c++ ${CLANGXX_PATH}" 245CMDL="${CMDL} --use-analyzer ${CLANGXX_PATH}" 246CMDL="${CMDL} -o ${OUT_DIR}" 247CMDL="${CMDL} ${CHECKERS}" 248CMDL="${CMDL} make USE_CLANG=true" 249if [ "${DISABLE_UTEST}" = true ]; then 250 CMDL="$CMDL DISABLE_UTEST=true" 251fi 252CMDL="$CMDL CC=${SCAN_BUILD_PY_CC}" 253CMDL="$CMDL CXX=${SCAN_BUILD_PY_CXX}" 254CMDL="$CMDL -j32" 255if [ ! -z "${BUILD_TARGET}" ]; then 256 CMDL="$CMDL ${BUILD_TARGET}" 257fi 258 259# Execute 260$CMDL 261 262exit 0; 263