Summary: Use the output of `clang -###` to drive which commands to run. Attach the plugin to all commands starting with `-cc1`. Benefits: - support for compiling multiple files in one clang command, eg `infer -- clang -c file1.c file2.c` - support for compile commands that do not target a `.o` file, eg `infer -- clang -S hello.c` - support for `-cc1` compile commands - more generally, run all commands that clang would run, and attach plugin in all compilation cases Reviewed By: martinoluca Differential Revision: D3366912 fbshipit-source-id: 98d5e3bmaster
parent
1810ef1408
commit
596823bd32
@ -0,0 +1,177 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This source code is licensed under the BSD style license found in the
|
||||||
|
# LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
# of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
# Given the arguments a `clang -cc1 ...` command, attaches a plugin to
|
||||||
|
# the clang command, then run our own clang with all the arguments
|
||||||
|
# (passing through filter_args_and_run_fcp_clang.sh) and pipe the
|
||||||
|
# output to InferClang.
|
||||||
|
|
||||||
|
#### Configuration ####
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
BIN_DIR="${SCRIPT_DIR}/../../bin"
|
||||||
|
ETC_DIR="${SCRIPT_DIR}/../../etc"
|
||||||
|
|
||||||
|
# path to the wrapped clang compiler to invoke
|
||||||
|
CLANG_COMPILER="${SCRIPT_DIR}/filter_args_and_run_fcp_clang"
|
||||||
|
# extension of the file containing the clang cmd intercepted
|
||||||
|
CMD_FILE_EXT=".sh"
|
||||||
|
# extension of the file containing the output of the Infer Clang frontend
|
||||||
|
INFERCLANG_LOG_FILE_EXT=".astlog"
|
||||||
|
# path of the plugin to load in clang
|
||||||
|
PLUGIN_PATH="${SCRIPT_DIR}/../../../facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib"
|
||||||
|
# name of the plugin to use
|
||||||
|
PLUGIN_NAME="BiniouASTExporter"
|
||||||
|
# output directory of the plugin
|
||||||
|
RESULTS_DIR="$FCP_RESULTS_DIR"
|
||||||
|
# this skips the creation of .o files
|
||||||
|
SYNTAX_ONLY="$FCP_RUN_SYNTAX_ONLY"
|
||||||
|
# extra arguments to pass during the execution of the infer frontend
|
||||||
|
INFER_FRONTEND_ARGS=($FCP_INFER_FRONTEND_ARGS)
|
||||||
|
# this fails the execution of clang if the frontend fails
|
||||||
|
REPORT_FRONTEND_FAILURE="$FCP_REPORT_FRONTEND_FAILURE"
|
||||||
|
# enable debug mode (to get more data saved to disk for future inspections)
|
||||||
|
DEBUG_MODE="$FCP_DEBUG_MODE"
|
||||||
|
# specify where is located Apple's clang
|
||||||
|
APPLE_CLANG="$FCP_APPLE_CLANG"
|
||||||
|
# whether to amend include search path with C++ model headers
|
||||||
|
INFER_CXX_MODELS="$FCP_INFER_CXX_MODELS"
|
||||||
|
|
||||||
|
# invariants that this script expects
|
||||||
|
if [ -z "$RESULTS_DIR" ]; then
|
||||||
|
echo '$FCP_RESULTS_DIR with the name of the output directory not provided.' 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ "$1" != "-cc1" ]; then
|
||||||
|
echo "$0 expects to be run with -cc1" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# we know the first argument is "-cc1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
function get_option_argument {
|
||||||
|
# retrieves the value passed to an argument of a clang command
|
||||||
|
OPT="$1"
|
||||||
|
shift
|
||||||
|
while [ -n "$1" ] && [ "$1" != "$OPT" ]; do shift; done
|
||||||
|
echo "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
function has_flag {
|
||||||
|
# return if the given flag is part of the given command or not
|
||||||
|
local FLAG="$1"
|
||||||
|
shift
|
||||||
|
while [ -n "$1" ] && [ "$1" != "$FLAG" ]; do shift; done
|
||||||
|
[ -n "$1" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main
|
||||||
|
INPUT_ARGUMENTS=("$@")
|
||||||
|
|
||||||
|
# -cc1 has to be the first argument or clang will think it runs in driver mode
|
||||||
|
CLANG_CMD=("${CLANG_COMPILER}${XX}" "-cc1")
|
||||||
|
|
||||||
|
# It's important to place this option before other -isystem options.
|
||||||
|
if [ -n "$INFER_CXX_MODELS" ]; then
|
||||||
|
CLANG_CMD+=("-isystem" "${SCRIPT_DIR}/../../models/cpp/include")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# (t7400979) this is a workaround to avoid that clang crashes when the -fmodules flag
|
||||||
|
# and the YojsonASTExporter plugin are used. Since the -plugin argument disables
|
||||||
|
# the generation of .o files, we invoke apple clang again to generate the expected
|
||||||
|
# artifacts. This will keep xcodebuild plus all the sub-steps happy.
|
||||||
|
if [ -n "$APPLE_CLANG" ]; then
|
||||||
|
ADD_PLUGIN_FLAG="-plugin"
|
||||||
|
else
|
||||||
|
ADD_PLUGIN_FLAG="-add-plugin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
CLANG_CMD+=(
|
||||||
|
"-load"
|
||||||
|
"${PLUGIN_PATH}"
|
||||||
|
"$ADD_PLUGIN_FLAG"
|
||||||
|
"${PLUGIN_NAME}"
|
||||||
|
"-plugin-arg-${PLUGIN_NAME}"
|
||||||
|
"-"
|
||||||
|
"-plugin-arg-${PLUGIN_NAME}"
|
||||||
|
"PREPEND_CURRENT_DIR=1")
|
||||||
|
|
||||||
|
if [ -n "$SYNTAX_ONLY" ]; then
|
||||||
|
CLANG_CMD+=("-fsyntax-only")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$LLVM_MODE" ]; then
|
||||||
|
CLANG_CMD+=("-o" "-" "-g" "-S" "-emit-llvm")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add the remaining arguments
|
||||||
|
CLANG_CMD+=("$@")
|
||||||
|
|
||||||
|
# the source file is at the end of the command, match it with the wanted extensions
|
||||||
|
SOURCE_FILENAME="${INPUT_ARGUMENTS[${#INPUT_ARGUMENTS[@]} - 1]}"
|
||||||
|
|
||||||
|
if ! [[ "$SOURCE_FILENAME" = /* ]]; then
|
||||||
|
SOURCE_FILENAME="$(pwd)/$SOURCE_FILENAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$LLVM_MODE" ]; then
|
||||||
|
INFER_FRONTEND_CMD=(
|
||||||
|
"${BIN_DIR}/InferLLVM"
|
||||||
|
"-c" "$SOURCE_FILENAME"
|
||||||
|
"-results_dir" "$RESULTS_DIR"
|
||||||
|
"${INFER_FRONTEND_ARGS[@]}")
|
||||||
|
INFER_FRONTEND_LOG_FILE="/dev/stdout"
|
||||||
|
else
|
||||||
|
LANGUAGE=$(get_option_argument "-x" "${INPUT_ARGUMENTS[@]}")
|
||||||
|
if [ -n "$LANGUAGE" ]; then INFER_FRONTEND_ARGS+=("-x" "$LANGUAGE"); fi
|
||||||
|
if has_flag "-fobjc-arc" "${INPUT_ARGUMENTS[@]}"; then
|
||||||
|
INFER_FRONTEND_ARGS+=("-fobjc-arc");
|
||||||
|
fi
|
||||||
|
|
||||||
|
INFER_FRONTEND_CMD=(
|
||||||
|
"${BIN_DIR}/InferClang"
|
||||||
|
"-c" "$SOURCE_FILENAME"
|
||||||
|
"-results_dir" "$RESULTS_DIR"
|
||||||
|
"${INFER_FRONTEND_ARGS[@]}")
|
||||||
|
|
||||||
|
if [ -n "$DEBUG_MODE" ]; then
|
||||||
|
OBJECT_FILENAME="$(get_option_argument "-o" "${INPUT_ARGUMENTS[@]}")"
|
||||||
|
# Emit the clang command with the extra args piped to InferClang
|
||||||
|
echo "${CLANG_CMD[@]} " \
|
||||||
|
"| tee ${OBJECT_FILENAME}.biniou " \
|
||||||
|
"| ${INFER_FRONTEND_CMD[@]}" \
|
||||||
|
> "${OBJECT_FILENAME}${CMD_FILE_EXT}"
|
||||||
|
echo "bdump -x -d ${ETC_DIR}/clang_ast.dict -w '!!DUMMY!!' ${OBJECT_FILENAME}.biniou " \
|
||||||
|
"> ${OBJECT_FILENAME}.bdump" \
|
||||||
|
>> "${OBJECT_FILENAME}${CMD_FILE_EXT}"
|
||||||
|
# Emit the InferClang cmd used to run the frontend
|
||||||
|
INFER_FRONTEND_LOG_FILE="${OBJECT_FILENAME}${INFERCLANG_LOG_FILE_EXT}"
|
||||||
|
echo "${INFER_FRONTEND_CMD[@]}" > "$INFER_FRONTEND_LOG_FILE"
|
||||||
|
else
|
||||||
|
INFER_FRONTEND_LOG_FILE="/dev/null"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# run clang and pipe its output to InferClang/InferLLVM, or flush it in case the latter crashes
|
||||||
|
"${CLANG_CMD[@]}" | \
|
||||||
|
("${INFER_FRONTEND_CMD[@]}" || \
|
||||||
|
{ EC=$?; cat > /dev/null; exit $EC; }) \
|
||||||
|
>> "$INFER_FRONTEND_LOG_FILE" 2>&1
|
||||||
|
STATUSES=("${PIPESTATUS[@]}")
|
||||||
|
STATUS="${STATUSES[0]}"
|
||||||
|
INFER_STATUS="${STATUSES[1]}"
|
||||||
|
|
||||||
|
# if clang fails, then fail, otherwise, fail with the frontend's exitcode if required
|
||||||
|
if [ "$STATUS" == 0 ] && [ -n "$REPORT_FRONTEND_FAILURE" ]; then
|
||||||
|
STATUS="$INFER_STATUS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $STATUS
|
@ -1,205 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# Clang wrapper to inject the execution of a plugin and execute the infer frontend
|
|
||||||
|
|
||||||
# Initialization
|
|
||||||
PARENT=$(dirname "$0")
|
|
||||||
SCRIPT_DIR=$(cd "$PARENT" && pwd)
|
|
||||||
SCRIPT_DIR="${SCRIPT_DIR%/}"
|
|
||||||
BIN_DIR="${SCRIPT_DIR}/../../bin"
|
|
||||||
ETC_DIR="${SCRIPT_DIR}/../../etc"
|
|
||||||
|
|
||||||
#### Configuration ####
|
|
||||||
# path to the wrapped clang compiler to invoke
|
|
||||||
CLANG_COMPILER="${SCRIPT_DIR}/clang_wrapper"
|
|
||||||
# extension of the file containing the clang cmd intercepted
|
|
||||||
CMD_FILE_EXT=".sh"
|
|
||||||
# extenion of the file containing the output of the Infer Clang frontend
|
|
||||||
INFERCLANG_LOG_FILE_EXT=".astlog"
|
|
||||||
# path of the plugin to load in clang
|
|
||||||
CLANG_PLUGIN_REL_PATH="facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib"
|
|
||||||
PLUGIN_PATH="${SCRIPT_DIR}/../../../${CLANG_PLUGIN_REL_PATH}"
|
|
||||||
# name of the plugin to use
|
|
||||||
PLUGIN_NAME="BiniouASTExporter"
|
|
||||||
# output directory of the plugin
|
|
||||||
RESULTS_DIR="${FCP_RESULTS_DIR}"
|
|
||||||
# this forces the wrapper to invoke get_standard_commandline_args to get
|
|
||||||
# a more precise clang command with all the arguments in the right place (slow)
|
|
||||||
USE_STD_CLANG_CMD="${FCP_USE_STD_CLANG_CMD}"
|
|
||||||
# this skips the creation of .o files
|
|
||||||
SYNTAX_ONLY="${FCP_RUN_SYNTAX_ONLY}"
|
|
||||||
# extra arguments to pass during the execution of the infer frontend
|
|
||||||
INFER_FRONTEND_ARGS=($FCP_INFER_FRONTEND_ARGS)
|
|
||||||
# this fails the execution of clang if the frontend fails
|
|
||||||
REPORT_FRONTEND_FAILURE="${FCP_REPORT_FRONTEND_FAILURE}"
|
|
||||||
# enable debug mode (to get more data saved to disk for future inspections)
|
|
||||||
DEBUG_MODE="${FCP_DEBUG_MODE}"
|
|
||||||
# specify where is located Apple's clang
|
|
||||||
APPLE_CLANG="${FCP_APPLE_CLANG}"
|
|
||||||
# whether to amend include search path with C++ model headers
|
|
||||||
INFER_CXX_MODELS="${FCP_INFER_CXX_MODELS}"
|
|
||||||
|
|
||||||
if [ -z "$RESULTS_DIR" ]; then
|
|
||||||
echo '$FCP_RESULTS_DIR with the name of the output directory not provided.' > /dev/stderr
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${0%++}" != "$0" ]; then XX="++"; else XX=""; fi
|
|
||||||
|
|
||||||
EXTRA_INCLUDE_PATH=()
|
|
||||||
if [ -n "$INFER_CXX_MODELS" ]; then
|
|
||||||
EXTRA_INCLUDE_PATH+=("-isystem")
|
|
||||||
EXTRA_INCLUDE_PATH+=("${SCRIPT_DIR}/../../models/cpp/include")
|
|
||||||
fi
|
|
||||||
|
|
||||||
CLANG_CMD=("${CLANG_COMPILER}${XX}" "${EXTRA_INCLUDE_PATH[@]}" "$@")
|
|
||||||
CWD=$(pwd)
|
|
||||||
CWD="${CWD%/}"
|
|
||||||
[ ! -d "$RESULTS_DIR" ] && mkdir -p "$RESULTS_DIR"
|
|
||||||
|
|
||||||
# Functions
|
|
||||||
function get_option_argument {
|
|
||||||
# retrieves the value passed to an argument of a clang command
|
|
||||||
OPT="$1"
|
|
||||||
shift
|
|
||||||
while [ -n "$1" ] && [ "$1" != "$OPT" ]; do shift; done
|
|
||||||
echo "$2"
|
|
||||||
}
|
|
||||||
|
|
||||||
function has_flag {
|
|
||||||
# return if the given flag is part of the given command or not
|
|
||||||
local FLAG="$1"
|
|
||||||
shift
|
|
||||||
while [ -n "$1" ] && [ "$1" != "$FLAG" ]; do shift; done
|
|
||||||
[ -n "$1" ]; echo "$?"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main
|
|
||||||
INPUT_ARGUMENTS=("$@")
|
|
||||||
if [ -n "$USE_STD_CLANG_CMD" ]; then
|
|
||||||
# this will run clang with the -### argument to get the command in a more
|
|
||||||
# standard format.
|
|
||||||
# Slow since it spawns clang as a separate process
|
|
||||||
STD_CMD="$($CLANG_COMPILER$XX -### "$@" 2>&1 | grep '^[[:space:]]\"' -m 1)"
|
|
||||||
# use sed to split all the arguments, and remove their surrounding double quotes
|
|
||||||
SED_CMD=$(echo "$STD_CMD" | sed -e 's/" "/\'$'\n/g' -e 's/^[[:space:]]*"//' -e 's/"[[:space:]]*$//')
|
|
||||||
IFS=$'\n'
|
|
||||||
# create an array of arguments using newline as separator
|
|
||||||
INPUT_ARGUMENTS=($SED_CMD)
|
|
||||||
unset IFS
|
|
||||||
fi
|
|
||||||
|
|
||||||
OBJECT_FILENAME="$(get_option_argument "-o" "${INPUT_ARGUMENTS[@]}")"
|
|
||||||
|
|
||||||
if echo "$OBJECT_FILENAME" | grep -q "\.o$"
|
|
||||||
then
|
|
||||||
# get the source file name
|
|
||||||
if [ -n "$USE_STD_CLANG_CMD" ]; then
|
|
||||||
# the source file is at the end of the command, match it with the wanted extensions
|
|
||||||
SOURCE_FILE=$(echo ${INPUT_ARGUMENTS[${#INPUT_ARGUMENTS[@]} - 1]})
|
|
||||||
else
|
|
||||||
# in this case we search for the argument after -c, match it with the wanted extensions
|
|
||||||
SOURCE_FILE=$(get_option_argument "-c" "${INPUT_ARGUMENTS[@]}")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$SOURCE_FILE" ]
|
|
||||||
then
|
|
||||||
# (t7400979) this is a workaround to avoid that clang crashes when the -fmodules flag
|
|
||||||
# and the YojsonASTExporter plugin are used. Since the -plugin argument disables
|
|
||||||
# the generation of .o files, we invoke apple clang again to generate the expected
|
|
||||||
# artifacts. This will keep xcodebuild plus all the sub-steps happy.
|
|
||||||
if [ -n "$APPLE_CLANG" ]; then
|
|
||||||
ADD_PLUGIN_FLAG="-plugin"
|
|
||||||
else
|
|
||||||
ADD_PLUGIN_FLAG="-add-plugin"
|
|
||||||
fi
|
|
||||||
if [ -z "$LLVM_MODE" ]; then
|
|
||||||
ATTACH_PLUGIN="1"
|
|
||||||
fi
|
|
||||||
IFS=$'\n'
|
|
||||||
if [ -n "$ATTACH_PLUGIN" ]; then
|
|
||||||
EXTRA_ARGS=("-Xclang" "-load"
|
|
||||||
"-Xclang" "${PLUGIN_PATH}"
|
|
||||||
"-Xclang" "$ADD_PLUGIN_FLAG"
|
|
||||||
"-Xclang" "${PLUGIN_NAME}"
|
|
||||||
"-Xclang" "-plugin-arg-${PLUGIN_NAME}"
|
|
||||||
"-Xclang" "-"
|
|
||||||
"-Xclang" "-plugin-arg-${PLUGIN_NAME}"
|
|
||||||
"-Xclang" "PREPEND_CURRENT_DIR=1")
|
|
||||||
fi
|
|
||||||
if [ -n "$SYNTAX_ONLY" ]; then
|
|
||||||
EXTRA_ARGS+=("-fsyntax-only")
|
|
||||||
fi
|
|
||||||
unset IFS
|
|
||||||
|
|
||||||
if [ -n "$LLVM_MODE" ]; then
|
|
||||||
EXTRA_ARGS+=("-o" "-" "-g" "-S" "-emit-llvm")
|
|
||||||
fi
|
|
||||||
|
|
||||||
# using always the original clang command for several reasons:
|
|
||||||
# - to avoid handling the presence/absence of -Xclang if the standard command is used
|
|
||||||
# - to emit the same command that was captured by this wrapper
|
|
||||||
# - to invoke the linker, whenever is needed
|
|
||||||
CLANG_CMD+=("${EXTRA_ARGS[@]}")
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -n "$ATTACH_PLUGIN" ] || [ -n "$LLVM_MODE" ]; then
|
|
||||||
[[ "$SOURCE_FILE" = /* ]] || { SOURCE_FILE="${CWD}/$SOURCE_FILE"; }
|
|
||||||
|
|
||||||
if [ -n "$LLVM_MODE" ]; then
|
|
||||||
INFER_FRONTEND_CMD=(
|
|
||||||
"${BIN_DIR}/InferLLVM"
|
|
||||||
"-c" "$SOURCE_FILE"
|
|
||||||
"-results_dir" "$RESULTS_DIR"
|
|
||||||
"${INFER_FRONTEND_ARGS[@]}")
|
|
||||||
INFER_FRONTEND_LOG_FILE="/dev/stdout"
|
|
||||||
else
|
|
||||||
FOBJC_ARC_FLAG=$(has_flag "-fobjc-arc" "${INPUT_ARGUMENTS[@]}")
|
|
||||||
LANGUAGE=$(get_option_argument "-x" "${INPUT_ARGUMENTS[@]}")
|
|
||||||
if [ -n "$LANGUAGE" ]; then INFER_FRONTEND_ARGS+=("-x" "$LANGUAGE"); fi
|
|
||||||
if [ "$FOBJC_ARC_FLAG" == 0 ]; then INFER_FRONTEND_ARGS+=("-fobjc-arc"); fi
|
|
||||||
|
|
||||||
INFER_FRONTEND_CMD=(
|
|
||||||
"${BIN_DIR}/InferClang"
|
|
||||||
"-c" "$SOURCE_FILE"
|
|
||||||
"-results_dir" "$RESULTS_DIR"
|
|
||||||
"${INFER_FRONTEND_ARGS[@]}")
|
|
||||||
|
|
||||||
if [ -n "$DEBUG_MODE" ]; then
|
|
||||||
# Emit the clang command with the extra args piped to InferClang
|
|
||||||
echo "${CLANG_CMD[@]} " \
|
|
||||||
"| tee ${OBJECT_FILENAME}.biniou " \
|
|
||||||
"| ${INFER_FRONTEND_CMD[@]}" \
|
|
||||||
> "${OBJECT_FILENAME}${CMD_FILE_EXT}"
|
|
||||||
echo "bdump -x -d ${ETC_DIR}/clang_ast.dict -w '!!DUMMY!!' ${OBJECT_FILENAME}.biniou " \
|
|
||||||
"> ${OBJECT_FILENAME}.bdump" \
|
|
||||||
>> "${OBJECT_FILENAME}${CMD_FILE_EXT}"
|
|
||||||
# Emit the InferClang cmd used to run the frontend
|
|
||||||
INFER_FRONTEND_LOG_FILE="${OBJECT_FILENAME}${INFERCLANG_LOG_FILE_EXT}"
|
|
||||||
echo "${INFER_FRONTEND_CMD[@]}" > "$INFER_FRONTEND_LOG_FILE"
|
|
||||||
else
|
|
||||||
INFER_FRONTEND_LOG_FILE="/dev/null"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run clang and pipe its output to InferClang/InferLLVM, or flush it in case the latter crashes
|
|
||||||
"${CLANG_CMD[@]}" | ("${INFER_FRONTEND_CMD[@]}" || { EC=$?; cat > /dev/null; exit $EC; }) >> "$INFER_FRONTEND_LOG_FILE" 2>&1
|
|
||||||
STATUSES=("${PIPESTATUS[@]}")
|
|
||||||
STATUS="${STATUSES[0]}"
|
|
||||||
INFER_STATUS="${STATUSES[1]}"
|
|
||||||
|
|
||||||
# if clang fails, then fail, otherwise, fail with the frontend's exitcode if required
|
|
||||||
if [ "$STATUS" == 0 ] && [ -n "$REPORT_FRONTEND_FAILURE" ]; then
|
|
||||||
STATUS="$INFER_STATUS"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
"${CLANG_CMD[@]}"
|
|
||||||
STATUS=$?
|
|
||||||
fi
|
|
||||||
|
|
||||||
# run apple clang if required (and if any)
|
|
||||||
if [ -n "$APPLE_CLANG" ]; then
|
|
||||||
"${APPLE_CLANG}$XX" "$@" || exit $?
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $STATUS
|
|
@ -1 +0,0 @@
|
|||||||
clang_general_wrapper
|
|
@ -1 +0,0 @@
|
|||||||
clang_wrapper
|
|
@ -0,0 +1 @@
|
|||||||
|
filter_args_and_run_fcp_clang.sh
|
@ -0,0 +1 @@
|
|||||||
|
filter_args_and_run_fcp_clang.sh
|
@ -0,0 +1 @@
|
|||||||
|
hijack_and_normalize_clang_command.sh
|
@ -0,0 +1 @@
|
|||||||
|
hijack_and_normalize_clang_command.sh
|
@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Copyright (c) 2016 - present Facebook, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This source code is licensed under the BSD style license found in the
|
||||||
|
# LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
# of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
# Given the more-or-less raw arguments passed to clang as arguments,
|
||||||
|
# this normalizes them via `clang -###` if needed to call the script
|
||||||
|
# that actually attaches the plugin on each source file. Unless we
|
||||||
|
# don't want to attach the plugin, in which case just run the original
|
||||||
|
# command.
|
||||||
|
|
||||||
|
#### Configuration ####
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
# script to run our own clang
|
||||||
|
CLANG_COMPILER="${SCRIPT_DIR}/filter_args_and_run_fcp_clang"
|
||||||
|
# script to attach the plugin to clang -cc1 commands and run InferClang
|
||||||
|
CLANG_CC1_CAPTURE="${SCRIPT_DIR}/attach_plugin_and_run_clang_frontend.sh"
|
||||||
|
# path to Apple's clang
|
||||||
|
APPLE_CLANG="$FCP_APPLE_CLANG"
|
||||||
|
|
||||||
|
# Main
|
||||||
|
if [ "${0%++}" != "$0" ]; then XX="++"; fi
|
||||||
|
|
||||||
|
# Normalize clang command if not -cc1 already. -cc1 is always the first argument if present.
|
||||||
|
if [ "$1" = "-cc1" ]; then
|
||||||
|
"$CLANG_CC1_CAPTURE" "$@"
|
||||||
|
STATUS=$?
|
||||||
|
else
|
||||||
|
# Run `clang -###` to get one compile command per source file.
|
||||||
|
# Slow since it spawns clang as a separate process
|
||||||
|
#
|
||||||
|
# Generate a command containing all the commands in the output of `clang -###`. These are
|
||||||
|
# the lines that start with ' "/absolute/path/to/binary"'.
|
||||||
|
#
|
||||||
|
# In that command, replace /absolute/path/to/clang with our own wrapper, but only for the
|
||||||
|
# core compiler commands (those that start with "-cc1"). This means we'll capture all
|
||||||
|
# compilation commands (one per source file), without interfering with non-compiler commands
|
||||||
|
# (as they run with absolute paths, so they won't get captured again further down the line).
|
||||||
|
#
|
||||||
|
# Fail on errors: if we detect an error in the output of `clang -###`, we add the line
|
||||||
|
# `echo <error>; exit 1` to the generated command. This is because `clang -###` pretty much
|
||||||
|
# never fails, but warns of failures on stderr instead.
|
||||||
|
CC_COMMAND=$("$CLANG_COMPILER$XX" -### "$@" 2>&1 | \
|
||||||
|
# only keep lines that are commands or errors
|
||||||
|
grep -e '^\([[:space:]]\"\|clang: error:\)' | \
|
||||||
|
# replace -cc1 commands with our clang wrapper
|
||||||
|
sed -e "s#^[[:space:]]\"\([^\"]*\)\" \"-cc1\" \(.*\)\$# \"$CLANG_CC1_CAPTURE\" \"-cc1\" \2#g" | \
|
||||||
|
# replace error messages by failures
|
||||||
|
sed -e 's#^\(^clang: error:.*$\)#echo "\1"; exit 1#g' | \
|
||||||
|
# add trailing ; to each line
|
||||||
|
sed -e 's/$/;/g')
|
||||||
|
eval $CC_COMMAND
|
||||||
|
STATUS=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
# run Apple clang if required (and if any)
|
||||||
|
if [ -n "$APPLE_CLANG" ]; then
|
||||||
|
"$APPLE_CLANG$XX" "$@" || exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $STATUS
|
@ -0,0 +1 @@
|
|||||||
|
../../../../examples/hello.c
|
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2015 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void test2() {
|
||||||
|
int* s = NULL;
|
||||||
|
*s = 42;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"bug_type": "NULL_DEREFERENCE",
|
||||||
|
"file": "hello.c",
|
||||||
|
"procedure": "test"
|
||||||
|
}
|
||||||
|
]
|
@ -0,0 +1,12 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"bug_type": "NULL_DEREFERENCE",
|
||||||
|
"file": "hello.c",
|
||||||
|
"procedure": "test"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bug_type": "NULL_DEREFERENCE",
|
||||||
|
"file": "hello2.c",
|
||||||
|
"procedure": "test2"
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in new issue