| #!/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 <toolchain prefix> : path to the directory containing bin/clang" | |
| echo "-s <scan-build-py prefix> : path to the directory bin/scan-build" | |
| echo "-o <output dir> : path to output dir (default: AnalysisResult)" | |
| echo "-m <clang|zircon|all> : 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 <target> : 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; |