#!/bin/bash # Copyright 2016 The Fuchsia Authors # # Use of this source code is governed by a MIT-style # license that can be found in the LICENSE file or at # https://opensource.org/licenses/MIT # This script will perform static analyses provided by Clang Static analyzers # on Zircon. It requires either a prebuilt Clang toolchan or a Clang toolchain # built from official Clang repository. For instructions on how to obtain a # prebuilt toolchain or build the toolchain from scratch, please refer to # document at # https://fuchsia.googlesource.com/zircon/+/master/docs/getting_started.md set -eu ORIGINAL_CWD="$(pwd)" # These are the default checkers for clang and are always on by defualt, # unless they are explicitley disabled CHECKERS_DEFAULT_ON="\ apiModeling.google.GTest \ core.CallAndMessage \ core.DynamicTypePropagation \ 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.NewDelete \ cplusplus.NewDeleteLeaks \ cplusplus.SelfAssignment \ deadcode.DeadStores \ nullability.NullPassedToNonnull \ nullability.NullReturnedFromNonnull \ security.insecureAPI.UncheckedReturn \ security.insecureAPI.getpw \ security.insecureAPI.gets \ security.insecureAPI.mkstemp \ security.insecureAPI.mktemp \ security.insecureAPI.vfork \ unix.API \ unix.Malloc \ unix.MallocSizeof \ unix.MismatchedDeallocator \ unix.Vfork \ unix.cstring.BadSizeArg \ unix.cstring.NullArg \ " # Zircon specific checkers # Content may change in the future # TODO: This checker will only work after https://reviews.llvm.org/D36024 lands. CHECKERS_ZIRCON="alpha.zircon.ZirconHandleChecker" # Checkers that should be enabled CHECKERS_TO_ENABLE="" # Checkers that should be disabled CHECKERS_TO_DISABLE="" # Checkers Args that should be passed to Clang Static Analyzer CHECKERS="" func_disable_checkers() { # Disable default checkers for i in $CHECKERS_TO_DISABLE; do CHECKERS="$CHECKERS -disable-checker $i" done } func_enable_checkers() { # Enable the checkers stored in $CHECKERS_TO_ENABLE for i in $CHECKERS_TO_ENABLE; do CHECKERS="$CHECKERS -enable-checker $i" done } func_test_exist() { if [ ! -e "$1" ]; then echo "$1 does not exist! Please check your input. Aborting!" exit -1 fi } func_trap_handler() { cd "$ORIGINAL_CWD" exit -1 } # Register trap trap func_trap_handler SIGHUP SIGINT SIGTERM EXIT # Analyzer run mode. clang|zircon|all RUN_MODE="clang" # Path to python version of scan_build SCAN_BUILD_PY="" # Path to CC wrapper of scan_build_py SCAN_BUILD_PY_CC="" # Path to CXX wrapper of scan_build_py SCAN_BUILD_PY_CXX="" # Build target BUILD_TARGET="" # Path to clang CLANG_PATH="" # Path to clang++ CLANGXX_PATH="" # Path to toolchain TOOLCHAIN_PREFIX="" # Path to directory that contains scan-build-py/bin SCAN_BUILD_PY_PREFIX="" # Do not process unit tests flag DISABLE_UTEST=false function func_help { echo "help:" echo "-p : path to the directory containing bin/clang" echo "-s : path to the directory bin/scan-build" echo "-o : path to output dir (default: AnalysisResult)" echo "-m : run mode. clang mode will only enable checkers that" echo " is enabled by default. zircon mode will only enable" echo " zircon related checkers. all mode will enable both" echo " default checkers and zircon related checkers." echo " Default value is clang." echo "-t : build target. Default is x86" echo "-n : do not run analyzer on unit tests" echo "-h : for help" exit 1 } SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink SCRIPT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" SOURCE="$(readlink "$SOURCE")" # if $SOURCE was a relative symlink, we need to resolve it relative to the # path where the symlink file was located [[ "$SOURCE" != /* ]] && SOURCE="$SCRIPT_DIR/$SOURCE" done SCRIPT_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" ZIRCON_ROOT="$SCRIPT_DIR/.." # Path to output analysis results OUT_DIR="$ZIRCON_ROOT/AnalysisResult" # Read args from command line while getopts "p:s:t:o:m:hn" opt; do case $opt in p) TOOLCHAIN_PREFIX="$OPTARG";; s) SCAN_BUILD_PY_PREFIX="$OPTARG";; t) BUILD_TARGET="$OPTARG";; o) OUT_DIR="$OPTARG";; m) RUN_MODE="${OPTARG,,}";; h) func_help;; n) DISABLE_UTEST=true;; \?) echo "Inavlid option" func_help esac done # Determine the clang prefix if [ -z "$TOOLCHAIN_PREFIX" ]; then # User did not provide toolchain prefix # Assume user prefer prebuilt toolchain PREBUILT_DIR="$ZIRCON_ROOT/prebuilt/downloads" # Determine OS type OS_STR="$(uname)" if [ "$OS_STR" = "Darwin" ]; then PREBUILT_DIR="$PREBUILT_DIR/clang+llvm-x86_64-darwin" elif [ "$OS_STR" = "Linux" ]; then PREBUILT_DIR="$PREBUILT_DIR/clang+llvm-x86_64-linux" fi if [ ! -d "$PREBUILT_DIR" ]; then echo "Toolchain prefix is not defined and prebuilt toolchain has not yet been downloaded." echo "Abort!" exit -1 fi TOOLCHAIN_PREFIX="$PREBUILT_DIR" fi CLANG_PATH="$TOOLCHAIN_PREFIX/bin/clang" CLANGXX_PATH="$TOOLCHAIN_PREFIX/bin/clang++" # Check if clang exists func_test_exist "$CLANG_PATH" func_test_exist "$CLANGXX_PATH" # Looking for scan-build-py # Prebuild does not have scan-build-py if [ -z "$SCAN_BUILD_PY_PREFIX" ]; then # SCAN_BUILD_PY_PREFIX not defined # Try fuchsia/third_party SCAN_BUILD_PY_PREFIX="$ZIRCON_ROOT/../third_party/llvm/tools/clang/tools/scan-build-py" fi if [ ! -d "$SCAN_BUILD_PY_PREFIX" ]; then echo "scan-build-py is not found at $SCAN_BUILD_PY_PREFIX, Aborting!" exit -1 fi SCAN_BUILD_PY="$SCAN_BUILD_PY_PREFIX/bin/scan-build" SCAN_BUILD_PY_CC="$SCAN_BUILD_PY_PREFIX/bin/analyze-cc" SCAN_BUILD_PY_CXX="$SCAN_BUILD_PY_PREFIX/bin/analyze-c++" # Test if scan-build exists func_test_exist "$SCAN_BUILD_PY" func_test_exist "$SCAN_BUILD_PY_CC" func_test_exist "$SCAN_BUILD_PY_CXX" # Construct Checker Args that should be passed to scan-build if [ "$RUN_MODE" = "zircon" ]; then CHECKERS_TO_DISABLE="${CHECKERS_TO_DISABLE} ${CHECKERS_DEFAULT_ON}" CHECKERS_TO_ENABLE="${CHECKERS_TO_ENABLE} ${CHECKERS_ZIRCON}" elif [ "$RUN_MODE" = "all" ]; then CHECKERS_TO_ENABLE="${CHECKERS_TO_ENABLE} ${CHECKERS_ZIRCON}" fi func_disable_checkers func_enable_checkers # All clear, perform analysis # Change dir to zircon cd "$ZIRCON_ROOT" # Run scan-build on make if [ ! -z "${BUILD_TARGET}" ]; then make USE_CLANG=true "${BUILD_TARGET}" clean &> /dev/null else make USE_CLANG=true clean &> /dev/null fi CMDL="${SCAN_BUILD_PY}" CMDL="${CMDL} --use-cc ${CLANG_PATH}" CMDL="${CMDL} --use-c++ ${CLANGXX_PATH}" CMDL="${CMDL} --use-analyzer ${CLANGXX_PATH}" CMDL="${CMDL} -o ${OUT_DIR}" CMDL="${CMDL} ${CHECKERS}" CMDL="${CMDL} make USE_CLANG=true" if [ "${DISABLE_UTEST}" = true ]; then CMDL="$CMDL DISABLE_UTEST=true" fi CMDL="$CMDL CC=${SCAN_BUILD_PY_CC}" CMDL="$CMDL CXX=${SCAN_BUILD_PY_CXX}" CMDL="$CMDL -j32" if [ ! -z "${BUILD_TARGET}" ]; then CMDL="$CMDL ${BUILD_TARGET}" fi # Execute $CMDL exit 0;