forked from OSchip/llvm-project
[analyzer] Individual configuration options can be specified for checkers.
Reviewed by: Anna Zaks Original patch by: Aleksei Sidorin Differential Revision: http://reviews.llvm.org/D7905 llvm-svn: 231266
This commit is contained in:
parent
e1d882c726
commit
e40c71c10a
|
@ -28,6 +28,10 @@ class DiagnosticsEngine;
|
|||
class Preprocessor;
|
||||
class LangOptions;
|
||||
|
||||
namespace ento {
|
||||
class CheckerBase;
|
||||
}
|
||||
|
||||
/// Analysis - Set of available source code analyses.
|
||||
enum Analyses {
|
||||
#define ANALYSIS(NAME, CMDFLAG, DESC, SCOPE) NAME,
|
||||
|
@ -252,18 +256,102 @@ private:
|
|||
/// \sa getMaxNodesPerTopLevelFunction
|
||||
Optional<unsigned> MaxNodesPerTopLevelFunction;
|
||||
|
||||
/// A helper function that retrieves option for a given full-qualified
|
||||
/// checker name.
|
||||
/// Options for checkers can be specified via 'analyzer-config' command-line
|
||||
/// option.
|
||||
/// Example:
|
||||
/// @code-analyzer-config unix.Malloc:OptionName=CheckerOptionValue @endcode
|
||||
/// or @code-analyzer-config unix:OptionName=GroupOptionValue @endcode
|
||||
/// for groups of checkers.
|
||||
/// @param [in] CheckerName Full-qualified checker name, like
|
||||
/// alpha.unix.StreamChecker.
|
||||
/// @param [in] OptionName Name of the option to get.
|
||||
/// @param [in] Default Default value if no option is specified.
|
||||
/// @param [in] SearchInParents If set to true and the searched option was not
|
||||
/// specified for the given checker the options for the parent packages will
|
||||
/// be searched as well. The inner packages take precedence over the outer
|
||||
/// ones.
|
||||
/// @retval CheckerOptionValue An option for a checker if it was specified.
|
||||
/// @retval GroupOptionValue An option for group if it was specified and no
|
||||
/// checker-specific options were found. The closer group to checker,
|
||||
/// the more priority it has. For example, @c coregroup.subgroup has more
|
||||
/// priority than @c coregroup for @c coregroup.subgroup.CheckerName checker.
|
||||
/// @retval Default If nor checker option, nor group option was found.
|
||||
StringRef getCheckerOption(StringRef CheckerName, StringRef OptionName,
|
||||
StringRef Default,
|
||||
bool SearchInParents = false);
|
||||
|
||||
public:
|
||||
/// Interprets an option's string value as a boolean.
|
||||
/// Interprets an option's string value as a boolean. The "true" string is
|
||||
/// interpreted as true and the "false" string is interpreted as false.
|
||||
///
|
||||
/// Accepts the strings "true" and "false".
|
||||
/// If an option value is not provided, returns the given \p DefaultVal.
|
||||
bool getBooleanOption(StringRef Name, bool DefaultVal);
|
||||
/// @param [in] Name Name for option to retrieve.
|
||||
/// @param [in] DefaultVal Default value returned if no such option was
|
||||
/// specified.
|
||||
/// @param [in] C The optional checker parameter that can be used to restrict
|
||||
/// the search to the options of this particular checker (and its parents
|
||||
/// dependening on search mode).
|
||||
/// @param [in] SearchInParents If set to true and the searched option was not
|
||||
/// specified for the given checker the options for the parent packages will
|
||||
/// be searched as well. The inner packages take precedence over the outer
|
||||
/// ones.
|
||||
bool getBooleanOption(StringRef Name, bool DefaultVal,
|
||||
const ento::CheckerBase *C = nullptr,
|
||||
bool SearchInParents = false);
|
||||
|
||||
/// Variant that accepts a Optional value to cache the result.
|
||||
bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal);
|
||||
///
|
||||
/// @param [in,out] V Return value storage, returned if parameter contains
|
||||
/// an existing valid option, else it is used to store a return value
|
||||
/// @param [in] Name Name for option to retrieve.
|
||||
/// @param [in] DefaultVal Default value returned if no such option was
|
||||
/// specified.
|
||||
/// @param [in] C The optional checker parameter that can be used to restrict
|
||||
/// the search to the options of this particular checker (and its parents
|
||||
/// dependening on search mode).
|
||||
/// @param [in] SearchInParents If set to true and the searched option was not
|
||||
/// specified for the given checker the options for the parent packages will
|
||||
/// be searched as well. The inner packages take precedence over the outer
|
||||
/// ones.
|
||||
bool getBooleanOption(Optional<bool> &V, StringRef Name, bool DefaultVal,
|
||||
const ento::CheckerBase *C = nullptr,
|
||||
bool SearchInParents = false);
|
||||
|
||||
/// Interprets an option's string value as an integer value.
|
||||
int getOptionAsInteger(StringRef Name, int DefaultVal);
|
||||
///
|
||||
/// If an option value is not provided, returns the given \p DefaultVal.
|
||||
/// @param [in] Name Name for option to retrieve.
|
||||
/// @param [in] DefaultVal Default value returned if no such option was
|
||||
/// specified.
|
||||
/// @param [in] C The optional checker parameter that can be used to restrict
|
||||
/// the search to the options of this particular checker (and its parents
|
||||
/// dependening on search mode).
|
||||
/// @param [in] SearchInParents If set to true and the searched option was not
|
||||
/// specified for the given checker the options for the parent packages will
|
||||
/// be searched as well. The inner packages take precedence over the outer
|
||||
/// ones.
|
||||
int getOptionAsInteger(StringRef Name, int DefaultVal,
|
||||
const ento::CheckerBase *C = nullptr,
|
||||
bool SearchInParents = false);
|
||||
|
||||
/// Query an option's string value.
|
||||
///
|
||||
/// If an option value is not provided, returns the given \p DefaultVal.
|
||||
/// @param [in] Name Name for option to retrieve.
|
||||
/// @param [in] DefaultVal Default value returned if no such option was
|
||||
/// specified.
|
||||
/// @param [in] C The optional checker parameter that can be used to restrict
|
||||
/// the search to the options of this particular checker (and its parents
|
||||
/// dependening on search mode).
|
||||
/// @param [in] SearchInParents If set to true and the searched option was not
|
||||
/// specified for the given checker the options for the parent packages will
|
||||
/// be searched as well. The inner packages take precedence over the outer
|
||||
/// ones.
|
||||
StringRef getOptionAsString(StringRef Name, StringRef DefaultVal,
|
||||
const ento::CheckerBase *C = nullptr,
|
||||
bool SearchInParents = false);
|
||||
|
||||
/// \brief Retrieves and sets the UserMode. This is a high-level option,
|
||||
/// which is used to set other low-level options. It is not accessible
|
||||
|
|
|
@ -295,7 +295,7 @@ def UnixAPIChecker : Checker<"API">,
|
|||
HelpText<"Check calls to various UNIX/Posix functions">,
|
||||
DescFile<"UnixAPIChecker.cpp">;
|
||||
|
||||
def MallocPessimistic : Checker<"Malloc">,
|
||||
def MallocChecker: Checker<"Malloc">,
|
||||
HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
|
||||
DescFile<"MallocChecker.cpp">;
|
||||
|
||||
|
@ -315,10 +315,6 @@ def ChrootChecker : Checker<"Chroot">,
|
|||
HelpText<"Check improper use of chroot">,
|
||||
DescFile<"ChrootChecker.cpp">;
|
||||
|
||||
def MallocOptimistic : Checker<"MallocWithAnnotations">,
|
||||
HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free(). Assumes that all user-defined functions which might free a pointer are annotated.">,
|
||||
DescFile<"MallocChecker.cpp">;
|
||||
|
||||
def PthreadLockChecker : Checker<"PthreadLock">,
|
||||
HelpText<"Simple lock -> unlock checker">,
|
||||
DescFile<"PthreadLockChecker.cpp">;
|
||||
|
|
|
@ -170,8 +170,7 @@ public:
|
|||
/// In pessimistic mode, the checker assumes that it does not know which
|
||||
/// functions might free the memory.
|
||||
enum CheckKind {
|
||||
CK_MallocPessimistic,
|
||||
CK_MallocOptimistic,
|
||||
CK_MallocChecker,
|
||||
CK_NewDeleteChecker,
|
||||
CK_NewDeleteLeaksChecker,
|
||||
CK_MismatchedDeallocatorChecker,
|
||||
|
@ -184,6 +183,8 @@ public:
|
|||
MOK_Any
|
||||
};
|
||||
|
||||
DefaultBool IsOptimistic;
|
||||
|
||||
DefaultBool ChecksEnabled[CK_NumCheckKinds];
|
||||
CheckName CheckNames[CK_NumCheckKinds];
|
||||
typedef llvm::SmallVector<CheckKind, CK_NumCheckKinds> CKVecTy;
|
||||
|
@ -584,7 +585,7 @@ bool MallocChecker::isCMemFunction(const FunctionDecl *FD,
|
|||
if (Family != AF_Malloc)
|
||||
return false;
|
||||
|
||||
if (ChecksEnabled[CK_MallocOptimistic] && FD->hasAttrs()) {
|
||||
if (IsOptimistic && FD->hasAttrs()) {
|
||||
for (const auto *I : FD->specific_attrs<OwnershipAttr>()) {
|
||||
OwnershipAttr::OwnershipKind OwnKind = I->getOwnKind();
|
||||
if(OwnKind == OwnershipAttr::Takes || OwnKind == OwnershipAttr::Holds) {
|
||||
|
@ -791,8 +792,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
|
|||
}
|
||||
}
|
||||
|
||||
if (ChecksEnabled[CK_MallocOptimistic] ||
|
||||
ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
|
||||
if (IsOptimistic || ChecksEnabled[CK_MismatchedDeallocatorChecker]) {
|
||||
// Check all the attributes, if there are any.
|
||||
// There can be multiple of these attributes.
|
||||
if (FD->hasAttrs())
|
||||
|
@ -1362,8 +1362,7 @@ MallocChecker::getCheckIfTracked(MallocChecker::CheckKind CK,
|
|||
case AF_IfNameIndex:
|
||||
case AF_Alloca: {
|
||||
// C checkers.
|
||||
if (CK == CK_MallocOptimistic ||
|
||||
CK == CK_MallocPessimistic) {
|
||||
if (CK == CK_MallocChecker) {
|
||||
return CK;
|
||||
}
|
||||
return Optional<MallocChecker::CheckKind>();
|
||||
|
@ -1516,8 +1515,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
|||
SourceRange Range,
|
||||
const Expr *DeallocExpr) const {
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteChecker),
|
||||
C, DeallocExpr);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -1559,8 +1557,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
|||
void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
|
||||
SourceRange Range) const {
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_MismatchedDeallocatorChecker),
|
||||
AF_Alloca);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -1639,8 +1636,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|||
const Expr *AllocExpr) const {
|
||||
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteChecker),
|
||||
C, AllocExpr);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -1692,8 +1688,7 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal,
|
|||
void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
||||
SymbolRef Sym) const {
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteChecker),
|
||||
C, Sym);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -1718,8 +1713,7 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
|||
bool Released, SymbolRef Sym,
|
||||
SymbolRef PrevSym) const {
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteChecker),
|
||||
C, Sym);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -1934,8 +1928,7 @@ MallocChecker::getAllocationSite(const ExplodedNode *N, SymbolRef Sym,
|
|||
void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
||||
CheckerContext &C) const {
|
||||
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteLeaksChecker),
|
||||
C, Sym);
|
||||
if (!CheckKind.hasValue())
|
||||
|
@ -2058,8 +2051,7 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
|
|||
return;
|
||||
|
||||
ASTContext &Ctx = C.getASTContext();
|
||||
if ((ChecksEnabled[CK_MallocOptimistic] ||
|
||||
ChecksEnabled[CK_MallocPessimistic]) &&
|
||||
if (ChecksEnabled[CK_MallocChecker] &&
|
||||
(isCMemFunction(FD, Ctx, AF_Malloc, MemoryOperationKind::MOK_Free) ||
|
||||
isCMemFunction(FD, Ctx, AF_IfNameIndex,
|
||||
MemoryOperationKind::MOK_Free)))
|
||||
|
@ -2551,8 +2543,7 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
|
|||
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
|
||||
const RefState *RefS = State->get<RegionState>(I.getKey());
|
||||
AllocationFamily Family = RefS->getAllocationFamily();
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocOptimistic,
|
||||
CK_MallocPessimistic,
|
||||
auto CheckKind = getCheckIfTracked(MakeVecFromCK(CK_MallocChecker,
|
||||
CK_NewDeleteChecker),
|
||||
Family);
|
||||
I.getKey()->dumpToStream(Out);
|
||||
|
@ -2568,6 +2559,8 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
|
|||
void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
|
||||
registerCStringCheckerBasic(mgr);
|
||||
MallocChecker *checker = mgr.registerChecker<MallocChecker>();
|
||||
checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption(
|
||||
"Optimistic", false, checker);
|
||||
checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
|
||||
checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
|
||||
mgr.getCurrentCheckName();
|
||||
|
@ -2581,11 +2574,12 @@ void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
|
|||
void ento::register##name(CheckerManager &mgr) { \
|
||||
registerCStringCheckerBasic(mgr); \
|
||||
MallocChecker *checker = mgr.registerChecker<MallocChecker>(); \
|
||||
checker->IsOptimistic = mgr.getAnalyzerOptions().getBooleanOption( \
|
||||
"Optimistic", false, checker); \
|
||||
checker->ChecksEnabled[MallocChecker::CK_##name] = true; \
|
||||
checker->CheckNames[MallocChecker::CK_##name] = mgr.getCurrentCheckName(); \
|
||||
}
|
||||
|
||||
REGISTER_CHECKER(MallocPessimistic)
|
||||
REGISTER_CHECKER(MallocOptimistic)
|
||||
REGISTER_CHECKER(MallocChecker)
|
||||
REGISTER_CHECKER(NewDeleteChecker)
|
||||
REGISTER_CHECKER(MismatchedDeallocatorChecker)
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
using namespace llvm;
|
||||
|
||||
AnalyzerOptions::UserModeKind AnalyzerOptions::getUserMode() {
|
||||
|
@ -100,12 +102,37 @@ AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) {
|
|||
|
||||
static StringRef toString(bool b) { return b ? "true" : "false"; }
|
||||
|
||||
bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
|
||||
StringRef AnalyzerOptions::getCheckerOption(StringRef CheckerName,
|
||||
StringRef OptionName,
|
||||
StringRef Default,
|
||||
bool SearchInParents) {
|
||||
// Search for a package option if the option for the checker is not specified
|
||||
// and search in parents is enabled.
|
||||
ConfigTable::const_iterator E = Config.end();
|
||||
do {
|
||||
ConfigTable::const_iterator I =
|
||||
Config.find((Twine(CheckerName) + ":" + OptionName).str());
|
||||
if (I != E)
|
||||
return StringRef(I->getValue());
|
||||
size_t Pos = CheckerName.rfind('.');
|
||||
if (Pos == StringRef::npos)
|
||||
return Default;
|
||||
CheckerName = CheckerName.substr(0, Pos);
|
||||
} while (!CheckerName.empty() && SearchInParents);
|
||||
return Default;
|
||||
}
|
||||
|
||||
bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal,
|
||||
const CheckerBase *C,
|
||||
bool SearchInParents) {
|
||||
// FIXME: We should emit a warning here if the value is something other than
|
||||
// "true", "false", or the empty string (meaning the default value),
|
||||
// but the AnalyzerOptions doesn't have access to a diagnostic engine.
|
||||
StringRef Default = toString(DefaultVal);
|
||||
StringRef V =
|
||||
Config.insert(std::make_pair(Name, toString(DefaultVal))).first->second;
|
||||
C ? getCheckerOption(C->getTagDescription(), Name, Default,
|
||||
SearchInParents)
|
||||
: StringRef(Config.insert(std::make_pair(Name, Default)).first->second);
|
||||
return llvm::StringSwitch<bool>(V)
|
||||
.Case("true", true)
|
||||
.Case("false", false)
|
||||
|
@ -113,9 +140,10 @@ bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) {
|
|||
}
|
||||
|
||||
bool AnalyzerOptions::getBooleanOption(Optional<bool> &V, StringRef Name,
|
||||
bool DefaultVal) {
|
||||
bool DefaultVal, const CheckerBase *C,
|
||||
bool SearchInParents) {
|
||||
if (!V.hasValue())
|
||||
V = getBooleanOption(Name, DefaultVal);
|
||||
V = getBooleanOption(Name, DefaultVal, C, SearchInParents);
|
||||
return V.getValue();
|
||||
}
|
||||
|
||||
|
@ -199,19 +227,35 @@ bool AnalyzerOptions::shouldWriteStableReportFilename() {
|
|||
/* Default = */ false);
|
||||
}
|
||||
|
||||
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) {
|
||||
int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal,
|
||||
const CheckerBase *C,
|
||||
bool SearchInParents) {
|
||||
SmallString<10> StrBuf;
|
||||
llvm::raw_svector_ostream OS(StrBuf);
|
||||
OS << DefaultVal;
|
||||
|
||||
StringRef V = Config.insert(std::make_pair(Name, OS.str())).first->second;
|
||||
StringRef V = C ? getCheckerOption(C->getTagDescription(), Name, OS.str(),
|
||||
SearchInParents)
|
||||
: StringRef(Config.insert(std::make_pair(Name, OS.str()))
|
||||
.first->second);
|
||||
|
||||
int Res = DefaultVal;
|
||||
bool b = V.getAsInteger(10, Res);
|
||||
assert(!b && "analyzer-config option should be numeric");
|
||||
(void) b;
|
||||
(void)b;
|
||||
return Res;
|
||||
}
|
||||
|
||||
StringRef AnalyzerOptions::getOptionAsString(StringRef Name,
|
||||
StringRef DefaultVal,
|
||||
const CheckerBase *C,
|
||||
bool SearchInParents) {
|
||||
return C ? getCheckerOption(C->getTagDescription(), Name, DefaultVal,
|
||||
SearchInParents)
|
||||
: StringRef(
|
||||
Config.insert(std::make_pair(Name, DefaultVal)).first->second);
|
||||
}
|
||||
|
||||
unsigned AnalyzerOptions::getAlwaysInlineSize() {
|
||||
if (!AlwaysInlineSize.hasValue())
|
||||
AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3);
|
||||
|
@ -281,4 +325,3 @@ bool AnalyzerOptions::shouldPrunePaths() {
|
|||
bool AnalyzerOptions::shouldConditionalizeStaticInitializers() {
|
||||
return getBooleanOption("cfg-conditional-static-initializers", true);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,alpha.unix.MallocWithAnnotations -fblocks -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-store=region -analyzer-checker=core,unix.Malloc -fblocks -verify -analyzer-config unix.Malloc:Optimistic=true %s
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void free(void *);
|
||||
void *alloca(size_t);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,alpha.unix.MallocWithAnnotations -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.deadcode.UnreachableCode,alpha.core.CastSize,unix.Malloc -analyzer-store=region -verify -analyzer-config unix.Malloc:Optimistic=true %s
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void *malloc(size_t);
|
||||
void free(void *);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,alpha.unix,alpha.security.ArrayBound -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -Wno-array-bounds -analyze -analyzer-checker=core,unix,alpha.security.ArrayBound -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
|
||||
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void *malloc(size_t);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,alpha.unix,core.uninitialized -analyzer-store=region -verify %s
|
||||
// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix,core.uninitialized -analyzer-store=region -verify -analyzer-config unix:Optimistic=true %s
|
||||
typedef __typeof(sizeof(int)) size_t;
|
||||
void *malloc(size_t);
|
||||
void free(void *);
|
||||
|
|
|
@ -13,6 +13,7 @@ add_subdirectory(Basic)
|
|||
add_subdirectory(Lex)
|
||||
add_subdirectory(Driver)
|
||||
if(CLANG_ENABLE_STATIC_ANALYZER)
|
||||
add_subdirectory(StaticAnalyzer)
|
||||
add_subdirectory(Frontend)
|
||||
endif()
|
||||
add_subdirectory(ASTMatchers)
|
||||
|
|
|
@ -20,7 +20,7 @@ PARALLEL_DIRS = CodeGen Basic Lex Driver Format ASTMatchers AST Tooling \
|
|||
include $(CLANG_LEVEL)/../..//Makefile.config
|
||||
|
||||
ifeq ($(ENABLE_CLANG_ARCMT),1)
|
||||
PARALLEL_DIRS += Frontend libclang
|
||||
PARALLEL_DIRS += Frontend libclang StaticAnalyzer
|
||||
endif
|
||||
|
||||
endif # CLANG_LEVEL
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
//===- unittest/Analysis/AnalyzerOptionsTest.cpp - SA Options test --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
|
||||
TEST(StaticAnalyzerOptions, SearchInParentPackageTests) {
|
||||
AnalyzerOptions Opts;
|
||||
Opts.Config["Outer.Inner.CheckerOne:Option"] = "true";
|
||||
Opts.Config["Outer.Inner:Option"] = "false";
|
||||
Opts.Config["Outer.Inner:Option2"] = "true";
|
||||
Opts.Config["Outer:Option2"] = "false";
|
||||
|
||||
struct CheckerOneMock : CheckerBase {
|
||||
StringRef getTagDescription() const override {
|
||||
return "Outer.Inner.CheckerOne";
|
||||
}
|
||||
};
|
||||
struct CheckerTwoMock : CheckerBase {
|
||||
StringRef getTagDescription() const override {
|
||||
return "Outer.Inner.CheckerTwo";
|
||||
}
|
||||
};
|
||||
|
||||
// Checker one has Option specified as true. It should read true regardless of
|
||||
// search mode.
|
||||
CheckerOneMock CheckerOne;
|
||||
EXPECT_TRUE(Opts.getBooleanOption("Option", false, &CheckerOne));
|
||||
// The package option is overriden with a checker option.
|
||||
EXPECT_TRUE(Opts.getBooleanOption("Option", false, &CheckerOne, true));
|
||||
// The Outer package option is overriden by the Inner package option. No
|
||||
// package option is specified.
|
||||
EXPECT_TRUE(Opts.getBooleanOption("Option2", false, &CheckerOne, true));
|
||||
// No package option is specified and search in packages is turned off. The
|
||||
// default value should be returned.
|
||||
EXPECT_FALSE(Opts.getBooleanOption("Option2", false, &CheckerOne));
|
||||
EXPECT_TRUE(Opts.getBooleanOption("Option2", true, &CheckerOne));
|
||||
|
||||
// Checker true has no option specified. It should get the default value when
|
||||
// search in parents turned off and false when search in parents turned on.
|
||||
CheckerTwoMock CheckerTwo;
|
||||
EXPECT_FALSE(Opts.getBooleanOption("Option", false, &CheckerTwo));
|
||||
EXPECT_TRUE(Opts.getBooleanOption("Option", true, &CheckerTwo));
|
||||
EXPECT_FALSE(Opts.getBooleanOption("Option", true, &CheckerTwo, true));
|
||||
}
|
||||
|
||||
TEST(StaticAnalyzerOptions, StringOptions) {
|
||||
AnalyzerOptions Opts;
|
||||
Opts.Config["Outer.Inner.CheckerOne:Option"] = "StringValue";
|
||||
|
||||
struct CheckerOneMock : CheckerBase {
|
||||
StringRef getTagDescription() const override {
|
||||
return "Outer.Inner.CheckerOne";
|
||||
}
|
||||
};
|
||||
|
||||
CheckerOneMock CheckerOne;
|
||||
EXPECT_TRUE("StringValue" ==
|
||||
Opts.getOptionAsString("Option", "DefaultValue", &CheckerOne));
|
||||
EXPECT_TRUE("DefaultValue" ==
|
||||
Opts.getOptionAsString("Option2", "DefaultValue", &CheckerOne));
|
||||
}
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
|
@ -0,0 +1,13 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
|
||||
add_clang_unittest(StaticAnalysisTests
|
||||
AnalyzerOptionsTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(StaticAnalysisTests
|
||||
clangBasic
|
||||
clangAnalysis
|
||||
clangStaticAnalyzerCore
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
##===- unittests/Basic/Makefile ----------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
CLANG_LEVEL = ../..
|
||||
TESTNAME = StaticAnalysis
|
||||
LINK_COMPONENTS := support mc
|
||||
USEDLIBS = clangBasic.a clangAnalysis.a clangStaticAnalyzerCore.a
|
||||
|
||||
include $(CLANG_LEVEL)/unittests/Makefile
|
Loading…
Reference in New Issue