| #!/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; |