blob: 2eae0712e7d8a78aa9953c52bf4a01dccd924bd4 [file] [log] [blame]
#!/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/fuchsia/+/master/zircon/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;