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