diff options
Diffstat (limited to 'include/clang/StaticAnalyzer')
27 files changed, 1004 insertions, 1026 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td index 11f1e5d4bd..15034fc689 100644 --- a/include/clang/StaticAnalyzer/Checkers/CheckerBase.td +++ b/include/clang/StaticAnalyzer/Checkers/CheckerBase.td @@ -11,29 +11,34 @@ // //===----------------------------------------------------------------------===// -class CheckerGroup<string name> { - string GroupName = name; -} -class InGroup<CheckerGroup G> { CheckerGroup Group = G; } - +/// Describes a package. Every checker is a part of a package, for example, +/// 'NullDereference' is part of the 'core' package, hence it's full name is +/// 'core.NullDereference'. +/// Example: +/// def Core : Package<"core">; class Package<string name> { string PackageName = name; - bit Hidden = 0; Package ParentPackage; - CheckerGroup Group; } -class InPackage<Package P> { Package ParentPackage = P; } -// All checkers are an indirect subclass of this. +/// Describes a 'super' package that holds another package inside it. This is +/// used to nest packages in one another. One may, for example, create the +/// 'builtin' package inside 'core', thus creating the package 'core.builtin'. +/// Example: +/// def CoreBuiltin : Package<"builtin">, ParentPackage<Core>; +class ParentPackage<Package P> { Package ParentPackage = P; } + +/// A description. May be displayed to the user when clang is invoked with +/// a '-help'-like command line option. +class HelpText<string text> { string HelpText = text; } + +/// Describes a checker. Every builtin checker has to be registered with the use +/// of this class (out-of-trunk checkers loaded from plugins obviously don't). +/// Note that a checker has a name (e.g.: 'NullDereference'), and a fullname, +/// that is autogenerated with the help of the ParentPackage field, that also +/// includes package names (e.g.: 'core.NullDereference'). class Checker<string name = ""> { string CheckerName = name; - string DescFile; string HelpText; - bit Hidden = 0; Package ParentPackage; - CheckerGroup Group; } - -class DescFile<string filename> { string DescFile = filename; } -class HelpText<string text> { string HelpText = text; } -class Hidden { bit Hidden = 1; } diff --git a/include/clang/StaticAnalyzer/Checkers/Checkers.td b/include/clang/StaticAnalyzer/Checkers/Checkers.td index 435bf6023a..9feb5a8766 100644 --- a/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -21,9 +21,9 @@ include "CheckerBase.td" def Alpha : Package<"alpha">; def Core : Package<"core">; -def CoreBuiltin : Package<"builtin">, InPackage<Core>; -def CoreUninitialized : Package<"uninitialized">, InPackage<Core>; -def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden; +def CoreBuiltin : Package<"builtin">, ParentPackage<Core>; +def CoreUninitialized : Package<"uninitialized">, ParentPackage<Core>; +def CoreAlpha : Package<"core">, ParentPackage<Alpha>; // The OptIn package is for checkers that are not alpha and that would normally // be on by default but where the driver does not have enough information to @@ -41,58 +41,59 @@ def OptIn : Package<"optin">; // In the Portability package reside checkers for finding code that relies on // implementation-defined behavior. Such checks are wanted for cross-platform // development, but unwanted for developers who target only a single platform. -def PortabilityOptIn : Package<"portability">, InPackage<OptIn>; +def PortabilityOptIn : Package<"portability">, ParentPackage<OptIn>; def Nullability : Package<"nullability">; def Cplusplus : Package<"cplusplus">; -def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden; -def CplusplusOptIn : Package<"cplusplus">, InPackage<OptIn>; +def CplusplusAlpha : Package<"cplusplus">, ParentPackage<Alpha>; +def CplusplusOptIn : Package<"cplusplus">, ParentPackage<OptIn>; def Valist : Package<"valist">; def DeadCode : Package<"deadcode">; -def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden; +def DeadCodeAlpha : Package<"deadcode">, ParentPackage<Alpha>; -def Performance : Package<"performance">, InPackage<OptIn>; +def Performance : Package<"performance">, ParentPackage<OptIn>; def Security : Package <"security">; -def InsecureAPI : Package<"insecureAPI">, InPackage<Security>; -def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden; -def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden; +def InsecureAPI : Package<"insecureAPI">, ParentPackage<Security>; +def SecurityAlpha : Package<"security">, ParentPackage<Alpha>; +def Taint : Package<"taint">, ParentPackage<SecurityAlpha>; def Unix : Package<"unix">; -def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden; -def CString : Package<"cstring">, InPackage<Unix>, Hidden; -def CStringAlpha : Package<"cstring">, InPackage<UnixAlpha>, Hidden; +def UnixAlpha : Package<"unix">, ParentPackage<Alpha>; +def CString : Package<"cstring">, ParentPackage<Unix>; +def CStringAlpha : Package<"cstring">, ParentPackage<UnixAlpha>; def OSX : Package<"osx">; -def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden; -def OSXOptIn : Package<"osx">, InPackage<OptIn>; +def OSXAlpha : Package<"osx">, ParentPackage<Alpha>; +def OSXOptIn : Package<"osx">, ParentPackage<OptIn>; -def Cocoa : Package<"cocoa">, InPackage<OSX>; -def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden; -def CocoaOptIn : Package<"cocoa">, InPackage<OSXOptIn>; +def Cocoa : Package<"cocoa">, ParentPackage<OSX>; +def CocoaAlpha : Package<"cocoa">, ParentPackage<OSXAlpha>; +def CocoaOptIn : Package<"cocoa">, ParentPackage<OSXOptIn>; -def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>; -def Containers : Package<"containers">, InPackage<CoreFoundation>; +def CoreFoundation : Package<"coreFoundation">, ParentPackage<OSX>; +def Containers : Package<"containers">, ParentPackage<CoreFoundation>; -def LocalizabilityAlpha : Package<"localizability">, InPackage<CocoaAlpha>; -def LocalizabilityOptIn : Package<"localizability">, InPackage<CocoaOptIn>; +def LocalizabilityAlpha : Package<"localizability">, ParentPackage<CocoaAlpha>; +def LocalizabilityOptIn : Package<"localizability">, ParentPackage<CocoaOptIn>; -def MPI : Package<"mpi">, InPackage<OptIn>; +def MPI : Package<"mpi">, ParentPackage<OptIn>; def LLVM : Package<"llvm">; +def LLVMAlpha : Package<"llvm">, ParentPackage<Alpha>; // The APIModeling package is for checkers that model APIs and don't perform // any diagnostics. These checkers are always turned on; this package is // intended for API modeling that is not controlled by the target triple. -def APIModeling : Package<"apiModeling">, Hidden; -def GoogleAPIModeling : Package<"google">, InPackage<APIModeling>; +def APIModeling : Package<"apiModeling">; +def GoogleAPIModeling : Package<"google">, ParentPackage<APIModeling>; def Debug : Package<"debug">; -def CloneDetectionAlpha : Package<"clone">, InPackage<Alpha>, Hidden; +def CloneDetectionAlpha : Package<"clone">, ParentPackage<Alpha>; //===----------------------------------------------------------------------===// // Core Checkers. @@ -101,130 +102,120 @@ def CloneDetectionAlpha : Package<"clone">, InPackage<Alpha>, Hidden; let ParentPackage = Core in { def DereferenceChecker : Checker<"NullDereference">, - HelpText<"Check for dereferences of null pointers">, - DescFile<"DereferenceChecker.cpp">; + HelpText<"Check for dereferences of null pointers">; def CallAndMessageChecker : Checker<"CallAndMessage">, - HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">, - DescFile<"CallAndMessageChecker.cpp">; + HelpText<"Check for logical errors for function calls and Objective-C " + "message expressions (e.g., uninitialized arguments, null function " + "pointers)">; def NonNullParamChecker : Checker<"NonNullParamChecker">, - HelpText<"Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute">, - DescFile<"NonNullParamChecker.cpp">; + HelpText<"Check for null pointers passed as arguments to a function whose " + "arguments are references or marked with the 'nonnull' attribute">; def VLASizeChecker : Checker<"VLASize">, - HelpText<"Check for declarations of VLA of undefined or zero size">, - DescFile<"VLASizeChecker.cpp">; + HelpText<"Check for declarations of VLA of undefined or zero size">; def DivZeroChecker : Checker<"DivideZero">, - HelpText<"Check for division by zero">, - DescFile<"DivZeroChecker.cpp">; + HelpText<"Check for division by zero">; def UndefResultChecker : Checker<"UndefinedBinaryOperatorResult">, - HelpText<"Check for undefined results of binary operators">, - DescFile<"UndefResultChecker.cpp">; + HelpText<"Check for undefined results of binary operators">; def StackAddrEscapeChecker : Checker<"StackAddressEscape">, - HelpText<"Check that addresses to stack memory do not escape the function">, - DescFile<"StackAddrEscapeChecker.cpp">; + HelpText<"Check that addresses to stack memory do not escape the function">; def DynamicTypePropagation : Checker<"DynamicTypePropagation">, - HelpText<"Generate dynamic type information">, - DescFile<"DynamicTypePropagation.cpp">; + HelpText<"Generate dynamic type information">; def NonnullGlobalConstantsChecker: Checker<"NonnilStringConstants">, - HelpText<"Assume that const string-like globals are non-null">, - DescFile<"NonilStringConstantsChecker.cpp">; + HelpText<"Assume that const string-like globals are non-null">; } // end "core" let ParentPackage = CoreAlpha in { def BoolAssignmentChecker : Checker<"BoolAssignment">, - HelpText<"Warn about assigning non-{0,1} values to Boolean variables">, - DescFile<"BoolAssignmentChecker.cpp">; + HelpText<"Warn about assigning non-{0,1} values to Boolean variables">; def CastSizeChecker : Checker<"CastSize">, - HelpText<"Check when casting a malloc'ed type T, whether the size is a multiple of the size of T">, - DescFile<"CastSizeChecker.cpp">; + HelpText<"Check when casting a malloc'ed type T, whether the size is a " + "multiple of the size of T">; def CastToStructChecker : Checker<"CastToStruct">, - HelpText<"Check for cast from non-struct pointer to struct pointer">, - DescFile<"CastToStructChecker.cpp">; + HelpText<"Check for cast from non-struct pointer to struct pointer">; def ConversionChecker : Checker<"Conversion">, - HelpText<"Loss of sign/precision in implicit conversions">, - DescFile<"ConversionChecker.cpp">; + HelpText<"Loss of sign/precision in implicit conversions">; def IdenticalExprChecker : Checker<"IdenticalExpr">, - HelpText<"Warn about unintended use of identical expressions in operators">, - DescFile<"IdenticalExprChecker.cpp">; + HelpText<"Warn about unintended use of identical expressions in operators">; def FixedAddressChecker : Checker<"FixedAddr">, - HelpText<"Check for assignment of a fixed address to a pointer">, - DescFile<"FixedAddressChecker.cpp">; + HelpText<"Check for assignment of a fixed address to a pointer">; def PointerArithChecker : Checker<"PointerArithm">, - HelpText<"Check for pointer arithmetic on locations other than array elements">, - DescFile<"PointerArithChecker">; + HelpText<"Check for pointer arithmetic on locations other than array " + "elements">; def PointerSubChecker : Checker<"PointerSub">, - HelpText<"Check for pointer subtractions on two pointers pointing to different memory chunks">, - DescFile<"PointerSubChecker">; + HelpText<"Check for pointer subtractions on two pointers pointing to " + "different memory chunks">; def SizeofPointerChecker : Checker<"SizeofPtr">, - HelpText<"Warn about unintended use of sizeof() on pointer expressions">, - DescFile<"CheckSizeofPointer.cpp">; + HelpText<"Warn about unintended use of sizeof() on pointer expressions">; def CallAndMessageUnInitRefArg : Checker<"CallAndMessageUnInitRefArg">, - HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables)">, - DescFile<"CallAndMessageChecker.cpp">; + HelpText<"Check for logical errors for function calls and Objective-C " + "message expressions (e.g., uninitialized arguments, null function " + "pointers, and pointer to undefined variables)">; def TestAfterDivZeroChecker : Checker<"TestAfterDivZero">, - HelpText<"Check for division by variable that is later compared against 0. Either the comparison is useless or there is division by zero.">, - DescFile<"TestAfterDivZeroChecker.cpp">; + HelpText<"Check for division by variable that is later compared against 0. " + "Either the comparison is useless or there is division by zero.">; def DynamicTypeChecker : Checker<"DynamicTypeChecker">, - HelpText<"Check for cases where the dynamic and the static type of an object are unrelated.">, - DescFile<"DynamicTypeChecker.cpp">; + HelpText<"Check for cases where the dynamic and the static type of an object " + "are unrelated.">; def StackAddrAsyncEscapeChecker : Checker<"StackAddressAsyncEscape">, - HelpText<"Check that addresses to stack memory do not escape the function">, - DescFile<"StackAddrEscapeChecker.cpp">; + HelpText<"Check that addresses to stack memory do not escape the function">; } // end "alpha.core" let ParentPackage = Nullability in { def NullPassedToNonnullChecker : Checker<"NullPassedToNonnull">, - HelpText<"Warns when a null pointer is passed to a pointer which has a _Nonnull type.">, - DescFile<"NullabilityChecker.cpp">; + HelpText<"Warns when a null pointer is passed to a pointer which has a " + "_Nonnull type.">; def NullReturnedFromNonnullChecker : Checker<"NullReturnedFromNonnull">, - HelpText<"Warns when a null pointer is returned from a function that has _Nonnull return type.">, - DescFile<"NullabilityChecker.cpp">; + HelpText<"Warns when a null pointer is returned from a function that has " + "_Nonnull return type.">; def NullableDereferencedChecker : Checker<"NullableDereferenced">, - HelpText<"Warns when a nullable pointer is dereferenced.">, - DescFile<"NullabilityChecker.cpp">; + HelpText<"Warns when a nullable pointer is dereferenced.">; def NullablePassedToNonnullChecker : Checker<"NullablePassedToNonnull">, - HelpText<"Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.">, - DescFile<"NullabilityChecker.cpp">; + HelpText<"Warns when a nullable pointer is passed to a pointer which has a " + "_Nonnull type.">; def NullableReturnedFromNonnullChecker : Checker<"NullableReturnedFromNonnull">, - HelpText<"Warns when a nullable pointer is returned from a function that has _Nonnull return type.">, - DescFile<"NullabilityChecker.cpp">; + HelpText<"Warns when a nullable pointer is returned from a function that has " + "_Nonnull return type.">; } // end "nullability" let ParentPackage = APIModeling in { +def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">, + HelpText<"Improve modeling of the C standard library functions">; + def TrustNonnullChecker : Checker<"TrustNonnull">, - HelpText<"Trust that returns from framework methods annotated with _Nonnull are not null">, - DescFile<"TrustNonnullChecker.cpp">; + HelpText<"Trust that returns from framework methods annotated with _Nonnull " + "are not null">; -} +} // end "apiModeling" //===----------------------------------------------------------------------===// // Evaluate "builtin" functions. @@ -233,12 +224,11 @@ def TrustNonnullChecker : Checker<"TrustNonnull">, let ParentPackage = CoreBuiltin in { def NoReturnFunctionChecker : Checker<"NoReturnFunctions">, - HelpText<"Evaluate \"panic\" functions that are known to not return to the caller">, - DescFile<"NoReturnFunctionChecker.cpp">; + HelpText<"Evaluate \"panic\" functions that are known to not return to the " + "caller">; def BuiltinFunctionChecker : Checker<"BuiltinFunctions">, - HelpText<"Evaluate compiler builtin functions (e.g., alloca())">, - DescFile<"BuiltinFunctionChecker.cpp">; + HelpText<"Evaluate compiler builtin functions (e.g., alloca())">; } // end "core.builtin" @@ -249,24 +239,19 @@ def BuiltinFunctionChecker : Checker<"BuiltinFunctions">, let ParentPackage = CoreUninitialized in { def UndefinedArraySubscriptChecker : Checker<"ArraySubscript">, - HelpText<"Check for uninitialized values used as array subscripts">, - DescFile<"UndefinedArraySubscriptChecker.cpp">; + HelpText<"Check for uninitialized values used as array subscripts">; def UndefinedAssignmentChecker : Checker<"Assign">, - HelpText<"Check for assigning uninitialized values">, - DescFile<"UndefinedAssignmentChecker.cpp">; + HelpText<"Check for assigning uninitialized values">; def UndefBranchChecker : Checker<"Branch">, - HelpText<"Check for uninitialized values used as branch conditions">, - DescFile<"UndefBranchChecker.cpp">; + HelpText<"Check for uninitialized values used as branch conditions">; def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">, - HelpText<"Check for blocks that capture uninitialized values">, - DescFile<"UndefCapturedBlockVarChecker.cpp">; + HelpText<"Check for blocks that capture uninitialized values">; def ReturnUndefChecker : Checker<"UndefReturn">, - HelpText<"Check for uninitialized values being returned to the caller">, - DescFile<"ReturnUndefChecker.cpp">; + HelpText<"Check for uninitialized values being returned to the caller">; } // end "core.uninitialized" @@ -277,28 +262,25 @@ def ReturnUndefChecker : Checker<"UndefReturn">, let ParentPackage = Cplusplus in { def InnerPointerChecker : Checker<"InnerPointer">, - HelpText<"Check for inner pointers of C++ containers used after re/deallocation">, - DescFile<"InnerPointerChecker.cpp">; + HelpText<"Check for inner pointers of C++ containers used after " + "re/deallocation">; def NewDeleteChecker : Checker<"NewDelete">, - HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">, - DescFile<"MallocChecker.cpp">; + HelpText<"Check for double-free and use-after-free problems. Traces memory " + "managed by new/delete.">; def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">, - HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, - DescFile<"MallocChecker.cpp">; + HelpText<"Check for memory leaks. Traces memory managed by new/delete.">; def CXXSelfAssignmentChecker : Checker<"SelfAssignment">, - HelpText<"Checks C++ copy and move assignment operators for self assignment">, - DescFile<"CXXSelfAssignmentChecker.cpp">; + HelpText<"Checks C++ copy and move assignment operators for self assignment">; } // end: "cplusplus" let ParentPackage = CplusplusOptIn in { def VirtualCallChecker : Checker<"VirtualCall">, - HelpText<"Check virtual function calls during construction or destruction">, - DescFile<"VirtualCallChecker.cpp">; + HelpText<"Check virtual function calls during construction or destruction">; } // end: "optin.cplusplus" @@ -306,29 +288,26 @@ let ParentPackage = CplusplusAlpha in { def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">, HelpText<"Reports destructions of polymorphic objects with a non-virtual " - "destructor in their base class">, - DescFile<"DeleteWithNonVirtualDtorChecker.cpp">; + "destructor in their base class">; + +def EnumCastOutOfRangeChecker : Checker<"EnumCastOutOfRange">, + HelpText<"Check integer to enumeration casts for out of range values">; def InvalidatedIteratorChecker : Checker<"InvalidatedIterator">, - HelpText<"Check for use of invalidated iterators">, - DescFile<"IteratorChecker.cpp">; + HelpText<"Check for use of invalidated iterators">; def IteratorRangeChecker : Checker<"IteratorRange">, - HelpText<"Check for iterators used outside their valid ranges">, - DescFile<"IteratorChecker.cpp">; + HelpText<"Check for iterators used outside their valid ranges">; def MismatchedIteratorChecker : Checker<"MismatchedIterator">, - HelpText<"Check for use of iterators of different containers where iterators of the same container are expected">, - DescFile<"IteratorChecker.cpp">; + HelpText<"Check for use of iterators of different containers where iterators " + "of the same container are expected">; -def MisusedMovedObjectChecker: Checker<"MisusedMovedObject">, - HelpText<"Method calls on a moved-from object and copying a moved-from " - "object will be reported">, - DescFile<"MisusedMovedObjectChecker.cpp">; +def MoveChecker: Checker<"Move">, + HelpText<"Find use-after-move bugs in C++">; def UninitializedObjectChecker: Checker<"UninitializedObject">, - HelpText<"Reports uninitialized fields after object construction">, - DescFile<"UninitializedObjectChecker.cpp">; + HelpText<"Reports uninitialized fields after object construction">; } // end: "alpha.cplusplus" @@ -340,16 +319,13 @@ def UninitializedObjectChecker: Checker<"UninitializedObject">, let ParentPackage = Valist in { def UninitializedChecker : Checker<"Uninitialized">, - HelpText<"Check for usages of uninitialized (or already released) va_lists.">, - DescFile<"ValistChecker.cpp">; + HelpText<"Check for usages of uninitialized (or already released) va_lists.">; def UnterminatedChecker : Checker<"Unterminated">, - HelpText<"Check for va_lists which are not released by a va_end call.">, - DescFile<"ValistChecker.cpp">; + HelpText<"Check for va_lists which are not released by a va_end call.">; def CopyToSelfChecker : Checker<"CopyToSelf">, - HelpText<"Check for va_lists which are copied onto itself.">, - DescFile<"ValistChecker.cpp">; + HelpText<"Check for va_lists which are copied onto itself.">; } // end : "valist" @@ -360,15 +336,15 @@ def CopyToSelfChecker : Checker<"CopyToSelf">, let ParentPackage = DeadCode in { def DeadStoresChecker : Checker<"DeadStores">, - HelpText<"Check for values stored to variables that are never read afterwards">, - DescFile<"DeadStoresChecker.cpp">; + HelpText<"Check for values stored to variables that are never read " + "afterwards">; + } // end DeadCode let ParentPackage = DeadCodeAlpha in { def UnreachableCodeChecker : Checker<"UnreachableCode">, - HelpText<"Check unreachable code">, - DescFile<"UnreachableCodeChecker.cpp">; + HelpText<"Check unreachable code">; } // end "alpha.deadcode" @@ -379,8 +355,7 @@ def UnreachableCodeChecker : Checker<"UnreachableCode">, let ParentPackage = Performance in { def PaddingChecker : Checker<"Padding">, - HelpText<"Check for excessively padded structs.">, - DescFile<"PaddingChecker.cpp">; + HelpText<"Check for excessively padded structs.">; } // end: "padding" @@ -389,70 +364,61 @@ def PaddingChecker : Checker<"Padding">, //===----------------------------------------------------------------------===// let ParentPackage = InsecureAPI in { - def bcmp : Checker<"bcmp">, - HelpText<"Warn on uses of the 'bcmp' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def bcopy : Checker<"bcopy">, - HelpText<"Warn on uses of the 'bcopy' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def bzero : Checker<"bzero">, - HelpText<"Warn on uses of the 'bzero' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def gets : Checker<"gets">, - HelpText<"Warn on uses of the 'gets' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def getpw : Checker<"getpw">, - HelpText<"Warn on uses of the 'getpw' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def mktemp : Checker<"mktemp">, - HelpText<"Warn on uses of the 'mktemp' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def mkstemp : Checker<"mkstemp">, - HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format string">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def rand : Checker<"rand">, - HelpText<"Warn on uses of the 'rand', 'random', and related functions">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def strcpy : Checker<"strcpy">, - HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def vfork : Checker<"vfork">, - HelpText<"Warn on uses of the 'vfork' function">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; - def UncheckedReturn : Checker<"UncheckedReturn">, - HelpText<"Warn on uses of functions whose return values must be always checked">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; -} + +def bcmp : Checker<"bcmp">, + HelpText<"Warn on uses of the 'bcmp' function">; +def bcopy : Checker<"bcopy">, + HelpText<"Warn on uses of the 'bcopy' function">; +def bzero : Checker<"bzero">, + HelpText<"Warn on uses of the 'bzero' function">; +def gets : Checker<"gets">, + HelpText<"Warn on uses of the 'gets' function">; +def getpw : Checker<"getpw">, + HelpText<"Warn on uses of the 'getpw' function">; +def mktemp : Checker<"mktemp">, + HelpText<"Warn on uses of the 'mktemp' function">; +def mkstemp : Checker<"mkstemp">, + HelpText<"Warn when 'mkstemp' is passed fewer than 6 X's in the format " + "string">; +def rand : Checker<"rand">, + HelpText<"Warn on uses of the 'rand', 'random', and related functions">; +def strcpy : Checker<"strcpy">, + HelpText<"Warn on uses of the 'strcpy' and 'strcat' functions">; +def vfork : Checker<"vfork">, + HelpText<"Warn on uses of the 'vfork' function">; +def UncheckedReturn : Checker<"UncheckedReturn">, + HelpText<"Warn on uses of functions whose return values must be always " + "checked">; + +} // end "security.insecureAPI" + let ParentPackage = Security in { - def FloatLoopCounter : Checker<"FloatLoopCounter">, - HelpText<"Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP)">, - DescFile<"CheckSecuritySyntaxOnly.cpp">; -} + +def FloatLoopCounter : Checker<"FloatLoopCounter">, + HelpText<"Warn on using a floating point value as a loop counter (CERT: " + "FLP30-C, FLP30-CPP)">; + +} // end "security" let ParentPackage = SecurityAlpha in { def ArrayBoundChecker : Checker<"ArrayBound">, - HelpText<"Warn about buffer overflows (older checker)">, - DescFile<"ArrayBoundChecker.cpp">; + HelpText<"Warn about buffer overflows (older checker)">; def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">, - HelpText<"Warn about buffer overflows (newer checker)">, - DescFile<"ArrayBoundCheckerV2.cpp">; + HelpText<"Warn about buffer overflows (newer checker)">; def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, - HelpText<"Check for an out-of-bound pointer being returned to callers">, - DescFile<"ReturnPointerRangeChecker.cpp">; + HelpText<"Check for an out-of-bound pointer being returned to callers">; def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, - HelpText<"Check for overflows in the arguments to malloc()">, - DescFile<"MallocOverflowSecurityChecker.cpp">; + HelpText<"Check for overflows in the arguments to malloc()">; // Operating systems specific PROT_READ/PROT_WRITE values is not implemented, // the defaults are correct for several common operating systems though, // but may need to be overridden via the related analyzer-config flags. def MmapWriteExecChecker : Checker<"MmapWriteExec">, - HelpText<"Warn on mmap() calls that are both writable and executable">, - DescFile<"MmapWriteExecChecker.cpp">; + HelpText<"Warn on mmap() calls that are both writable and executable">; } // end "alpha.security" @@ -463,8 +429,7 @@ def MmapWriteExecChecker : Checker<"MmapWriteExec">, let ParentPackage = Taint in { def GenericTaintChecker : Checker<"TaintPropagation">, - HelpText<"Generate taint information used by other checkers">, - DescFile<"GenericTaintChecker.cpp">; + HelpText<"Generate taint information used by other checkers">; } // end "alpha.security.taint" @@ -475,80 +440,66 @@ def GenericTaintChecker : Checker<"TaintPropagation">, let ParentPackage = Unix in { def UnixAPIMisuseChecker : Checker<"API">, - HelpText<"Check calls to various UNIX/Posix functions">, - DescFile<"UnixAPIChecker.cpp">; + HelpText<"Check calls to various UNIX/Posix functions">; 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">; + HelpText<"Check for memory leaks, double free, and use-after-free problems. " + "Traces memory managed by malloc()/free().">; def MallocSizeofChecker : Checker<"MallocSizeof">, - HelpText<"Check for dubious malloc arguments involving sizeof">, - DescFile<"MallocSizeofChecker.cpp">; + HelpText<"Check for dubious malloc arguments involving sizeof">; def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">, - HelpText<"Check for mismatched deallocators.">, - DescFile<"MallocChecker.cpp">; + HelpText<"Check for mismatched deallocators.">; def VforkChecker : Checker<"Vfork">, - HelpText<"Check for proper usage of vfork">, - DescFile<"VforkChecker.cpp">; - -def StdCLibraryFunctionsChecker : Checker<"StdCLibraryFunctions">, - HelpText<"Improve modeling of the C standard library functions">, - DescFile<"StdLibraryFunctionsChecker.cpp">; + HelpText<"Check for proper usage of vfork">; } // end "unix" let ParentPackage = UnixAlpha in { def ChrootChecker : Checker<"Chroot">, - HelpText<"Check improper use of chroot">, - DescFile<"ChrootChecker.cpp">; + HelpText<"Check improper use of chroot">; def PthreadLockChecker : Checker<"PthreadLock">, - HelpText<"Simple lock -> unlock checker">, - DescFile<"PthreadLockChecker.cpp">; + HelpText<"Simple lock -> unlock checker">; def StreamChecker : Checker<"Stream">, - HelpText<"Check stream handling functions">, - DescFile<"StreamChecker.cpp">; + HelpText<"Check stream handling functions">; def SimpleStreamChecker : Checker<"SimpleStream">, - HelpText<"Check for misuses of stream APIs">, - DescFile<"SimpleStreamChecker.cpp">; + HelpText<"Check for misuses of stream APIs">; def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">, - HelpText<"Check for calls to blocking functions inside a critical section">, - DescFile<"BlockInCriticalSectionChecker.cpp">; + HelpText<"Check for calls to blocking functions inside a critical section">; } // end "alpha.unix" let ParentPackage = CString in { def CStringNullArg : Checker<"NullArg">, - HelpText<"Check for null pointers being passed as arguments to C string functions">, - DescFile<"CStringChecker.cpp">; + HelpText<"Check for null pointers being passed as arguments to C string " + "functions">; def CStringSyntaxChecker : Checker<"BadSizeArg">, - HelpText<"Check the size argument passed into C string functions for common erroneous patterns">, - DescFile<"CStringSyntaxChecker.cpp">; -} + HelpText<"Check the size argument passed into C string functions for common " + "erroneous patterns">; + +} // end "unix.cstring" let ParentPackage = CStringAlpha in { def CStringOutOfBounds : Checker<"OutOfBounds">, - HelpText<"Check for out-of-bounds access in string functions">, - DescFile<"CStringChecker.cpp">; + HelpText<"Check for out-of-bounds access in string functions">; def CStringBufferOverlap : Checker<"BufferOverlap">, - HelpText<"Checks for overlap in two buffer arguments">, - DescFile<"CStringChecker.cpp">; + HelpText<"Checks for overlap in two buffer arguments">; def CStringNotNullTerm : Checker<"NotNullTerminated">, - HelpText<"Check for arguments which are not null-terminating strings">, - DescFile<"CStringChecker.cpp">; -} + HelpText<"Check for arguments which are not null-terminating strings">; + +} // end "alpha.unix.cstring" //===----------------------------------------------------------------------===// // Mac OS X, Cocoa, and Core Foundation checkers. @@ -557,193 +508,189 @@ def CStringNotNullTerm : Checker<"NotNullTerminated">, let ParentPackage = OSX in { def NumberObjectConversionChecker : Checker<"NumberObjectConversion">, - HelpText<"Check for erroneous conversions of objects representing numbers into numbers">, - DescFile<"NumberObjectConversionChecker.cpp">; + HelpText<"Check for erroneous conversions of objects representing numbers " + "into numbers">; def MacOSXAPIChecker : Checker<"API">, - HelpText<"Check for proper uses of various Apple APIs">, - DescFile<"MacOSXAPIChecker.cpp">; + HelpText<"Check for proper uses of various Apple APIs">; def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, - HelpText<"Check for proper uses of Secure Keychain APIs">, - DescFile<"MacOSKeychainAPIChecker.cpp">; + HelpText<"Check for proper uses of Secure Keychain APIs">; def ObjCPropertyChecker : Checker<"ObjCProperty">, - HelpText<"Check for proper uses of Objective-C properties">, - DescFile<"ObjCPropertyChecker.cpp">; + HelpText<"Check for proper uses of Objective-C properties">; + +def OSObjectRetainCountChecker : Checker<"OSObjectRetainCount">, + HelpText<"Check for leaks and improper reference count management for OSObject">; } // end "osx" let ParentPackage = Cocoa in { def RunLoopAutoreleaseLeakChecker : Checker<"RunLoopAutoreleaseLeak">, - HelpText<"Check for leaked memory in autorelease pools that will never be drained">, - DescFile<"RunLoopAutoreleaseLeakChecker.cpp">; + HelpText<"Check for leaked memory in autorelease pools that will never be " + "drained">; def ObjCAtSyncChecker : Checker<"AtSync">, - HelpText<"Check for nil pointers used as mutexes for @synchronized">, - DescFile<"ObjCAtSyncChecker.cpp">; + HelpText<"Check for nil pointers used as mutexes for @synchronized">; def NilArgChecker : Checker<"NilArg">, - HelpText<"Check for prohibited nil arguments to ObjC method calls">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Check for prohibited nil arguments to ObjC method calls">; def ClassReleaseChecker : Checker<"ClassRelease">, - HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly to a Class">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Check for sending 'retain', 'release', or 'autorelease' directly " + "to a Class">; def VariadicMethodTypeChecker : Checker<"VariadicMethodTypes">, HelpText<"Check for passing non-Objective-C types to variadic collection " - "initialization methods that expect only Objective-C types">, - DescFile<"BasicObjCFoundationChecks.cpp">; + "initialization methods that expect only Objective-C types">; def NSAutoreleasePoolChecker : Checker<"NSAutoreleasePool">, - HelpText<"Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode">, - DescFile<"NSAutoreleasePoolChecker.cpp">; + HelpText<"Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC " + "mode">; def ObjCMethSigsChecker : Checker<"IncompatibleMethodTypes">, - HelpText<"Warn about Objective-C method signatures with type incompatibilities">, - DescFile<"CheckObjCInstMethSignature.cpp">; + HelpText<"Warn about Objective-C method signatures with type " + "incompatibilities">; def ObjCUnusedIvarsChecker : Checker<"UnusedIvars">, - HelpText<"Warn about private ivars that are never used">, - DescFile<"ObjCUnusedIVarsChecker.cpp">; + HelpText<"Warn about private ivars that are never used">; def ObjCSelfInitChecker : Checker<"SelfInit">, - HelpText<"Check that 'self' is properly initialized inside an initializer method">, - DescFile<"ObjCSelfInitChecker.cpp">; + HelpText<"Check that 'self' is properly initialized inside an initializer " + "method">; def ObjCLoopChecker : Checker<"Loops">, - HelpText<"Improved modeling of loops using Cocoa collection types">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Improved modeling of loops using Cocoa collection types">; def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">, - HelpText<"Model the APIs that are guaranteed to return a non-nil value">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Model the APIs that are guaranteed to return a non-nil value">; def ObjCSuperCallChecker : Checker<"MissingSuperCall">, - HelpText<"Warn about Objective-C methods that lack a necessary call to super">, - DescFile<"ObjCMissingSuperCallChecker.cpp">; + HelpText<"Warn about Objective-C methods that lack a necessary call to " + "super">; def NSErrorChecker : Checker<"NSError">, - HelpText<"Check usage of NSError** parameters">, - DescFile<"NSErrorChecker.cpp">; + HelpText<"Check usage of NSError** parameters">; def RetainCountChecker : Checker<"RetainCount">, - HelpText<"Check for leaks and improper reference count management">, - DescFile<"RetainCountChecker.cpp">; + HelpText<"Check for leaks and improper reference count management">; def ObjCGenericsChecker : Checker<"ObjCGenerics">, - HelpText<"Check for type errors when using Objective-C generics">, - DescFile<"DynamicTypePropagation.cpp">; + HelpText<"Check for type errors when using Objective-C generics">; def ObjCDeallocChecker : Checker<"Dealloc">, - HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">, - DescFile<"CheckObjCDealloc.cpp">; + HelpText<"Warn about Objective-C classes that lack a correct implementation " + "of -dealloc">; def ObjCSuperDeallocChecker : Checker<"SuperDealloc">, - HelpText<"Warn about improper use of '[super dealloc]' in Objective-C">, - DescFile<"ObjCSuperDeallocChecker.cpp">; + HelpText<"Warn about improper use of '[super dealloc]' in Objective-C">; def AutoreleaseWriteChecker : Checker<"AutoreleaseWrite">, - HelpText<"Warn about potentially crashing writes to autoreleasing objects from different autoreleasing pools in Objective-C">, - DescFile<"ObjCAutoreleaseWriteChecker.cpp">; + HelpText<"Warn about potentially crashing writes to autoreleasing objects " + "from different autoreleasing pools in Objective-C">; + } // end "osx.cocoa" let ParentPackage = Performance in { def GCDAntipattern : Checker<"GCDAntipattern">, - HelpText<"Check for performance anti-patterns when using Grand Central Dispatch">, - DescFile<"GCDAntipatternChecker.cpp">; + HelpText<"Check for performance anti-patterns when using Grand Central " + "Dispatch">; } // end "optin.performance" let ParentPackage = CocoaAlpha in { def InstanceVariableInvalidation : Checker<"InstanceVariableInvalidation">, - HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">, - DescFile<"IvarInvalidationChecker.cpp">; + HelpText<"Check that the invalidatable instance variables are invalidated in " + "the methods annotated with objc_instance_variable_invalidator">; def MissingInvalidationMethod : Checker<"MissingInvalidationMethod">, - HelpText<"Check that the invalidation methods are present in classes that contain invalidatable instance variables">, - DescFile<"IvarInvalidationChecker.cpp">; + HelpText<"Check that the invalidation methods are present in classes that " + "contain invalidatable instance variables">; def DirectIvarAssignment : Checker<"DirectIvarAssignment">, - HelpText<"Check for direct assignments to instance variables">, - DescFile<"DirectIvarAssignment.cpp">; + HelpText<"Check for direct assignments to instance variables">; -def DirectIvarAssignmentForAnnotatedFunctions : Checker<"DirectIvarAssignmentForAnnotatedFunctions">, - HelpText<"Check for direct assignments to instance variables in the methods annotated with objc_no_direct_instance_variable_assignment">, - DescFile<"DirectIvarAssignment.cpp">; +def DirectIvarAssignmentForAnnotatedFunctions : + Checker<"DirectIvarAssignmentForAnnotatedFunctions">, + HelpText<"Check for direct assignments to instance variables in the methods " + "annotated with objc_no_direct_instance_variable_assignment">; } // end "alpha.osx.cocoa" let ParentPackage = CoreFoundation in { def CFNumberChecker : Checker<"CFNumber">, - HelpText<"Check for proper uses of CFNumber APIs">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Check for proper uses of CFNumber APIs">; def CFRetainReleaseChecker : Checker<"CFRetainRelease">, - HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">, - DescFile<"BasicObjCFoundationChecks.cpp">; + HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">; def CFErrorChecker : Checker<"CFError">, - HelpText<"Check usage of CFErrorRef* parameters">, - DescFile<"NSErrorChecker.cpp">; -} + HelpText<"Check usage of CFErrorRef* parameters">; + +} // end "osx.coreFoundation" let ParentPackage = Containers in { + def ObjCContainersASTChecker : Checker<"PointerSizedValues">, - HelpText<"Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with non-pointer-size values">, - DescFile<"ObjCContainersASTChecker.cpp">; + HelpText<"Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with " + "non-pointer-size values">; def ObjCContainersChecker : Checker<"OutOfBounds">, - HelpText<"Checks for index out-of-bounds when using 'CFArray' API">, - DescFile<"ObjCContainersChecker.cpp">; + HelpText<"Checks for index out-of-bounds when using 'CFArray' API">; -} +} // end "osx.coreFoundation.containers" let ParentPackage = LocalizabilityOptIn in { + def NonLocalizedStringChecker : Checker<"NonLocalizedStringChecker">, - HelpText<"Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings">, - DescFile<"LocalizationChecker.cpp">; + HelpText<"Warns about uses of non-localized NSStrings passed to UI methods " + "expecting localized NSStrings">; -def EmptyLocalizationContextChecker : Checker<"EmptyLocalizationContextChecker">, - HelpText<"Check that NSLocalizedString macros include a comment for context">, - DescFile<"LocalizationChecker.cpp">; -} +def EmptyLocalizationContextChecker : + Checker<"EmptyLocalizationContextChecker">, + HelpText<"Check that NSLocalizedString macros include a comment for context">; + +} // end "optin.osx.cocoa.localizability" let ParentPackage = LocalizabilityAlpha in { + def PluralMisuseChecker : Checker<"PluralMisuseChecker">, - HelpText<"Warns against using one vs. many plural pattern in code when generating localized strings.">, - DescFile<"LocalizationChecker.cpp">; -} + HelpText<"Warns against using one vs. many plural pattern in code when " + "generating localized strings.">; + +} // end "alpha.osx.cocoa.localizability" let ParentPackage = MPI in { - def MPIChecker : Checker<"MPI-Checker">, - HelpText<"Checks MPI code">, - DescFile<"MPIChecker.cpp">; -} + +def MPIChecker : Checker<"MPI-Checker">, + HelpText<"Checks MPI code">; + +} // end "optin.mpi" //===----------------------------------------------------------------------===// // Checkers for LLVM development. //===----------------------------------------------------------------------===// -def LLVMConventionsChecker : Checker<"Conventions">, - InPackage<LLVM>, - HelpText<"Check code for LLVM codebase conventions">, - DescFile<"LLVMConventionsChecker.cpp">; +let ParentPackage = LLVMAlpha in { +def LLVMConventionsChecker : Checker<"Conventions">, + HelpText<"Check code for LLVM codebase conventions">; +} // end "llvm" //===----------------------------------------------------------------------===// // Checkers modeling Google APIs. //===----------------------------------------------------------------------===// +let ParentPackage = GoogleAPIModeling in { + def GTestChecker : Checker<"GTest">, - InPackage<GoogleAPIModeling>, - HelpText<"Model gtest assertion APIs">, - DescFile<"GTestChecker.cpp">; + HelpText<"Model gtest assertion APIs">; + +} // end "apiModeling.google" //===----------------------------------------------------------------------===// // Debugging checkers (for analyzer development). @@ -752,60 +699,46 @@ def GTestChecker : Checker<"GTest">, let ParentPackage = Debug in { def AnalysisOrderChecker : Checker<"AnalysisOrder">, - HelpText<"Print callbacks that are called during analysis in order">, - DescFile<"AnalysisOrder.cpp">; + HelpText<"Print callbacks that are called during analysis in order">; def DominatorsTreeDumper : Checker<"DumpDominators">, - HelpText<"Print the dominance tree for a given CFG">, - DescFile<"DebugCheckers.cpp">; + HelpText<"Print the dominance tree for a given CFG">; def LiveVariablesDumper : Checker<"DumpLiveVars">, - HelpText<"Print results of live variable analysis">, - DescFile<"DebugCheckers.cpp">; + HelpText<"Print results of live variable analysis">; def CFGViewer : Checker<"ViewCFG">, - HelpText<"View Control-Flow Graphs using GraphViz">, - DescFile<"DebugCheckers.cpp">; + HelpText<"View Control-Flow Graphs using GraphViz">; def CFGDumper : Checker<"DumpCFG">, - HelpText<"Display Control-Flow Graphs">, - DescFile<"DebugCheckers.cpp">; + HelpText<"Display Control-Flow Graphs">; def CallGraphViewer : Checker<"ViewCallGraph">, - HelpText<"View Call Graph using GraphViz">, - DescFile<"DebugCheckers.cpp">; + HelpText<"View Call Graph using GraphViz">; def CallGraphDumper : Checker<"DumpCallGraph">, - HelpText<"Display Call Graph">, - DescFile<"DebugCheckers.cpp">; + HelpText<"Display Call Graph">; def ConfigDumper : Checker<"ConfigDumper">, - HelpText<"Dump config table">, - DescFile<"DebugCheckers.cpp">; + HelpText<"Dump config table">; def TraversalDumper : Checker<"DumpTraversal">, - HelpText<"Print branch conditions as they are traversed by the engine">, - DescFile<"TraversalChecker.cpp">; + HelpText<"Print branch conditions as they are traversed by the engine">; def CallDumper : Checker<"DumpCalls">, - HelpText<"Print calls as they are traversed by the engine">, - DescFile<"TraversalChecker.cpp">; + HelpText<"Print calls as they are traversed by the engine">; def AnalyzerStatsChecker : Checker<"Stats">, - HelpText<"Emit warnings with analyzer statistics">, - DescFile<"AnalyzerStatsChecker.cpp">; + HelpText<"Emit warnings with analyzer statistics">; def TaintTesterChecker : Checker<"TaintTest">, - HelpText<"Mark tainted symbols as such.">, - DescFile<"TaintTesterChecker.cpp">; + HelpText<"Mark tainted symbols as such.">; def ExprInspectionChecker : Checker<"ExprInspection">, - HelpText<"Check the analyzer's understanding of expressions">, - DescFile<"ExprInspectionChecker.cpp">; + HelpText<"Check the analyzer's understanding of expressions">; def ExplodedGraphViewer : Checker<"ViewExplodedGraph">, - HelpText<"View Exploded Graphs using GraphViz">, - DescFile<"DebugCheckers.cpp">; + HelpText<"View Exploded Graphs using GraphViz">; } // end "debug" @@ -817,8 +750,7 @@ def ExplodedGraphViewer : Checker<"ViewExplodedGraph">, let ParentPackage = CloneDetectionAlpha in { def CloneChecker : Checker<"CloneChecker">, - HelpText<"Reports similar pieces of code.">, - DescFile<"CloneChecker.cpp">; + HelpText<"Reports similar pieces of code.">; } // end "clone" @@ -829,7 +761,6 @@ def CloneChecker : Checker<"CloneChecker">, let ParentPackage = PortabilityOptIn in { def UnixAPIPortabilityChecker : Checker<"UnixAPI">, - HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">, - DescFile<"UnixAPIChecker.cpp">; + HelpText<"Finds implementation-defined behavior in UNIX/Posix functions">; } // end optin.portability diff --git a/include/clang/StaticAnalyzer/Core/Analyses.def b/include/clang/StaticAnalyzer/Core/Analyses.def index 281a2ac3a6..99e26c75e1 100644 --- a/include/clang/StaticAnalyzer/Core/Analyses.def +++ b/include/clang/StaticAnalyzer/Core/Analyses.def @@ -33,6 +33,7 @@ ANALYSIS_DIAGNOSTICS(HTML_SINGLE_FILE, "html-single-file", "Output analysis resu ANALYSIS_DIAGNOSTICS(PLIST, "plist", "Output analysis results using Plists", createPlistDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST_MULTI_FILE, "plist-multi-file", "Output analysis results using Plists (allowing for multi-file bugs)", createPlistMultiFileDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(PLIST_HTML, "plist-html", "Output analysis results using HTML wrapped with Plists", createPlistHTMLDiagnosticConsumer) +ANALYSIS_DIAGNOSTICS(SARIF, "sarif", "Output analysis results in a SARIF file", createSarifDiagnosticConsumer) ANALYSIS_DIAGNOSTICS(TEXT, "text", "Text output of analysis results", createTextPathDiagnosticConsumer) #ifndef ANALYSIS_PURGE diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def new file mode 100644 index 0000000000..8e5d8d3ad3 --- /dev/null +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def @@ -0,0 +1,377 @@ +//===-- AnalyzerOptions.def - Metadata about Static Analyses ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the analyzer options avaible with -analyzer-config. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGREF_H +#error This .def file is expected to be included in translation units where \ +"llvm/ADT/StringRef.h" is already included! +#endif + +#ifdef ANALYZER_OPTION +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +#error If you didnt include this file with the intent of generating methods, \ +define both 'ANALYZER_OPTION' and 'ANALYZER_OPTION_DEPENDS_ON_USER_MODE' macros! +#endif +#endif + +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +#ifdef ANALYZER_OPTION +#error If you didnt include this file with the intent of generating methods, \ +define both 'ANALYZER_OPTION' and 'ANALYZER_OPTION_DEPENDS_ON_USER_MODE' macros! +#endif +#endif + +#ifndef ANALYZER_OPTION +/// Create a new analyzer option, but dont generate a method for it in +/// AnalyzerOptions. +/// +/// TYPE - The type of the option object that will be stored in +/// AnalyzerOptions. This file is expected to be icluded in translation +/// units where AnalyzerOptions.h is included, so types from that +/// header should be used. +/// NAME - The name of the option object. +/// CMDFLAG - The command line flag for the option. +/// (-analyzer-config CMDFLAG=VALUE) +/// DESC - Description of the flag. +/// DEFAULT_VAL - The default value for CMDFLAG. +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) +#endif + +#ifndef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +/// Create a new analyzer option, but dont generate a method for it in +/// AnalyzerOptions. It's value depends on the option "user-mode". +/// +/// TYPE - The type of the option object that will be stored in +/// AnalyzerOptions. This file is expected to be icluded in translation +/// units where AnalyzerOptions.h is included, so types from that +/// header should be used. +/// NAME - The name of the option object. +/// CMDFLAG - The command line flag for the option. +/// (-analyzer-config CMDFLAG=VALUE) +/// DESC - Description of the flag. +/// SHALLOW_VAL - The default value for CMDFLAG, when "user-mode" was set to +/// "shallow". +/// DEEP_VAL - The default value for CMDFLAG, when "user-mode" was set to +/// "deep". +#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \ + SHALLOW_VAL, DEEP_VAL) +#endif + +//===----------------------------------------------------------------------===// +// The "mode" option. Since some options depend on this, we list it on top of +// this file in order to make sure that the generated field for it is +// initialized before the rest. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION( + StringRef, UserMode, "mode", + "(string) Controls the high-level analyzer mode, which influences the " + "default settings for some of the lower-level config options (such as " + "IPAMode). Value: \"deep\", \"shallow\".", + "deep") + +//===----------------------------------------------------------------------===// +// Boolean analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION(bool, ShouldIncludeImplicitDtorsInCFG, "cfg-implicit-dtors", + "Whether or not implicit destructors for C++ objects " + "should be included in the CFG.", + true) + +ANALYZER_OPTION(bool, ShouldIncludeTemporaryDtorsInCFG, "cfg-temporary-dtors", + "Whether or not the destructors for C++ temporary " + "objects should be included in the CFG.", + true) + +ANALYZER_OPTION( + bool, ShouldIncludeLifetimeInCFG, "cfg-lifetime", + "Whether or not end-of-lifetime information should be included in the CFG.", + false) + +ANALYZER_OPTION(bool, ShouldIncludeLoopExitInCFG, "cfg-loopexit", + "Whether or not the end of the loop information should " + "be included in the CFG.", + false) + +ANALYZER_OPTION(bool, ShouldIncludeRichConstructorsInCFG, + "cfg-rich-constructors", + "Whether or not construction site information should be " + "included in the CFG C++ constructor elements.", + true) + +ANALYZER_OPTION( + bool, ShouldIncludeScopesInCFG, "cfg-scopes", + "Whether or not scope information should be included in the CFG.", false) + +ANALYZER_OPTION( + bool, MayInlineTemplateFunctions, "c++-template-inlining", + "Whether or not templated functions may be considered for inlining.", true) + +ANALYZER_OPTION(bool, MayInlineCXXStandardLibrary, "c++-stdlib-inlining", + "Whether or not C++ standard library functions may be " + "considered for inlining.", + true) + +ANALYZER_OPTION(bool, MayInlineCXXAllocator, "c++-allocator-inlining", + "Whether or not allocator call may be considered for inlining.", + true) + +ANALYZER_OPTION( + bool, MayInlineCXXSharedPtrDtor, "c++-shared_ptr-inlining", + "Whether or not the destructor of C++ 'shared_ptr' may be considered for " + "inlining. This covers std::shared_ptr, std::tr1::shared_ptr, and " + "boost::shared_ptr, and indeed any destructor named '~shared_ptr'.", + false) + +ANALYZER_OPTION(bool, MayInlineCXXTemporaryDtors, "c++-temp-dtor-inlining", + "Whether C++ temporary destructors should be inlined " + "during analysis. If temporary destructors are disabled " + "in the CFG via the 'cfg-temporary-dtors' option, " + "temporary destructors would not be inlined anyway.", + true) + +ANALYZER_OPTION( + bool, ShouldSuppressNullReturnPaths, "suppress-null-return-paths", + "Whether or not paths that go through null returns should be suppressed. " + "This is a heuristic for avoiding bug reports with paths that go through " + "inlined functions that are more defensive than their callers.", + true) + +ANALYZER_OPTION( + bool, ShouldAvoidSuppressingNullArgumentPaths, + "avoid-suppressing-null-argument-paths", + "Whether a bug report should not be suppressed if its path includes a call " + "with a null argument, even if that call has a null return. This option " + "has no effect when ShouldSuppressNullReturnPaths is false. This is a " + "counter-heuristic to avoid false negatives.", + false) + +ANALYZER_OPTION(bool, ShouldSuppressInlinedDefensiveChecks, + "suppress-inlined-defensive-checks", + "Whether or not diagnostics containing inlined " + "defensive NULL checks should be suppressed.", + true) + +ANALYZER_OPTION(bool, MayInlineCXXContainerMethods, "c++-container-inlining", + "Whether or not methods of C++ container objects may be " + "considered for inlining.", + false) + +ANALYZER_OPTION(bool, ShouldSuppressFromCXXStandardLibrary, + "suppress-c++-stdlib", + "Whether or not diagnostics reported within the C++ " + "standard library should be suppressed.", + true) + +ANALYZER_OPTION(bool, ShouldCrosscheckWithZ3, "crosscheck-with-z3", + "Whether bug reports should be crosschecked with the Z3 " + "constraint manager backend.", + false) + +ANALYZER_OPTION(bool, ShouldReportIssuesInMainSourceFile, + "report-in-main-source-file", + "Whether or not the diagnostic report should be always " + "reported in the main source file and not the headers.", + false) + +ANALYZER_OPTION(bool, ShouldWriteStableReportFilename, "stable-report-filename", + "Whether or not the report filename should be random or not.", + false) + +ANALYZER_OPTION( + bool, ShouldSerializeStats, "serialize-stats", + "Whether the analyzer should serialize statistics to plist output. " + "Statistics would be serialized in JSON format inside the main dictionary " + "under the statistics key. Available only if compiled in assert mode or " + "with LLVM statistics explicitly enabled.", + false) + +ANALYZER_OPTION(bool, MayInlineObjCMethod, "objc-inlining", + "Whether ObjectiveC inlining is enabled, false otherwise.", + true) + +ANALYZER_OPTION(bool, ShouldPrunePaths, "prune-paths", + "Whether irrelevant parts of a bug report path should " + "be pruned out of the final output.", + true) + +ANALYZER_OPTION( + bool, ShouldConditionalizeStaticInitializers, + "cfg-conditional-static-initializers", + "Whether 'static' initializers should be in conditional logic in the CFG.", + true) + +ANALYZER_OPTION(bool, ShouldSynthesizeBodies, "faux-bodies", + "Whether the analyzer engine should synthesize fake " + "bodies for well-known functions.", + true) + +ANALYZER_OPTION( + bool, ShouldElideConstructors, "elide-constructors", + "Whether elidable C++ copy-constructors and move-constructors should be " + "actually elided during analysis. Both behaviors are allowed by the C++ " + "standard, and the analyzer, like CodeGen, defaults to eliding. Starting " + "with C++17 some elisions become mandatory, and in these cases the option " + "will be ignored.", + true) + +ANALYZER_OPTION( + bool, ShouldInlineLambdas, "inline-lambdas", + "Whether lambdas should be inlined. Otherwise a sink node will be " + "generated each time a LambdaExpr is visited.", + true) + +ANALYZER_OPTION(bool, ShouldWidenLoops, "widen-loops", + "Whether the analysis should try to widen loops.", false) + +ANALYZER_OPTION( + bool, ShouldUnrollLoops, "unroll-loops", + "Whether the analysis should try to unroll loops with known bounds.", false) + +ANALYZER_OPTION( + bool, ShouldDisplayNotesAsEvents, "notes-as-events", + "Whether the bug reporter should transparently treat extra note diagnostic " + "pieces as event diagnostic pieces. Useful when the diagnostic consumer " + "doesn't support the extra note pieces.", + false) + +ANALYZER_OPTION( + bool, ShouldAggressivelySimplifyBinaryOperation, + "aggressive-binary-operation-simplification", + "Whether SValBuilder should rearrange comparisons and additive operations " + "of symbolic expressions which consist of a sum of a symbol and a concrete " + "integer into the format where symbols are on the left-hand side and the " + "integer is on the right. This is only done if both symbols and both " + "concrete integers are signed, greater than or equal to the quarter of the " + "minimum value of the type and less than or equal to the quarter of the " + "maximum value of that type. A + n <OP> B + m becomes A - B <OP> m - n, " + "where A and B symbolic, n and m are integers. <OP> is any of '==', '!=', " + "'<', '<=', '>', '>=', '+' or '-'. The rearrangement also happens with '-' " + "instead of '+' on either or both side and also if any or both integers " + "are missing.", + false) + +ANALYZER_OPTION( + bool, ShouldEagerlyAssume, "eagerly-assume", + "Whether we should eagerly assume evaluations of conditionals, thus, " + "bifurcating the path. This indicates how the engine should handle " + "expressions such as: 'x = (y != 0)'. When this is true then the " + "subexpression 'y != 0' will be eagerly assumed to be true or false, thus " + "evaluating it to the integers 0 or 1 respectively. The upside is that " + "this can increase analysis precision until we have a better way to lazily " + "evaluate such logic. The downside is that it eagerly bifurcates paths.", + true) + +ANALYZER_OPTION( + bool, IsNaiveCTUEnabled, "experimental-enable-naive-ctu-analysis", + "Whether naive cross translation unit analysis is enabled. This is an " + "experimental feature to inline functions from another translation units.", + false) + +ANALYZER_OPTION(bool, ShouldDisplayMacroExpansions, "expand-macros", + "Whether macros related to the bugpath should be " + "expanded and included in the plist output.", + false) + +ANALYZER_OPTION(bool, DisplayCTUProgress, "display-ctu-progress", + "Whether to emit verbose output about " + "the analyzer's progress related to ctu.", + false) + +//===----------------------------------------------------------------------===// +// Unsinged analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION( + unsigned, AlwaysInlineSize, "ipa-always-inline-size", + "The size of the functions (in basic blocks), which should be considered " + "to be small enough to always inline.", + 3) + +ANALYZER_OPTION( + unsigned, GraphTrimInterval, "graph-trim-interval", + "How often nodes in the ExplodedGraph should be recycled to save memory. " + "To disable node reclamation, set the option to 0.", + 1000) + +ANALYZER_OPTION( + unsigned, MinCFGSizeTreatFunctionsAsLarge, + "min-cfg-size-treat-functions-as-large", + "The number of basic blocks a function needs to have to be considered " + "large for the 'max-times-inline-large' config option.", + 14) + +ANALYZER_OPTION(unsigned, MaxSymbolComplexity, "max-symbol-complexity", + "The maximum complexity of symbolic constraint.", 35) + +ANALYZER_OPTION(unsigned, MaxTimesInlineLarge, "max-times-inline-large", + "The maximum times a large function could be inlined.", 32) + +ANALYZER_OPTION_DEPENDS_ON_USER_MODE( + unsigned, MaxInlinableSize, "max-inlinable-size", + "The bound on the number of basic blocks in an inlined function.", + /* SHALLOW_VAL */ 4, /* DEEP_VAL */ 100) + +ANALYZER_OPTION_DEPENDS_ON_USER_MODE( + unsigned, MaxNodesPerTopLevelFunction, "max-nodes", + "The maximum number of nodes the analyzer can generate while exploring a " + "top level function (for each exploded graph). 0 means no limit.", + /* SHALLOW_VAL */ 75000, /* DEEP_VAL */ 225000) + +ANALYZER_OPTION( + unsigned, RegionStoreSmallStructLimit, "region-store-small-struct-limit", + "The largest number of fields a struct can have and still be considered " + "small This is currently used to decide whether or not it is worth forcing " + "a LazyCompoundVal on bind. To disable all small-struct-dependent " + "behavior, set the option to 0.", + 2) + +//===----------------------------------------------------------------------===// +// String analyzer options. +//===----------------------------------------------------------------------===// + +ANALYZER_OPTION(StringRef, CTUDir, "ctu-dir", + "The directory containing the CTU related files.", "") + +ANALYZER_OPTION(StringRef, CTUIndexName, "ctu-index-name", + "the name of the file containing the CTU index of functions.", + "externalFnMap.txt") + +ANALYZER_OPTION( + StringRef, ModelPath, "model-path", + "The analyzer can inline an alternative implementation written in C at the " + "call site if the called function's body is not available. This is a path " + "where to look for those alternative implementations (called models).", + "") + +ANALYZER_OPTION( + StringRef, CXXMemberInliningMode, "c++-inlining", + "Controls which C++ member functions will be considered for inlining. " + "Value: \"constructors\", \"destructors\", \"methods\".", + "destructors") + +ANALYZER_OPTION_DEPENDS_ON_USER_MODE( + StringRef, IPAMode, "ipa", + "Controls the mode of inter-procedural analysis. Value: \"none\", " + "\"basic-inlining\", \"inlining\", \"dynamic\", \"dynamic-bifurcate\".", + /* SHALLOW_VAL */ "inlining", /* DEEP_VAL */ "dynamic-bifurcate") + +ANALYZER_OPTION( + StringRef, ExplorationStrategy, "exploration_strategy", + "Value: \"dfs\", \"bfs\", \"unexplored_first\", " + "\"unexplored_first_queue\", \"unexplored_first_location_queue\", " + "\"bfs_block_dfs_contents\".", + "unexplored_first_queue") + +#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE +#undef ANALYZER_OPTION diff --git a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 715cc2bf23..7745e459e1 100644 --- a/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -20,6 +20,7 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include <string> #include <utility> #include <vector> @@ -85,7 +86,7 @@ enum CXXInlineableMemberKind { // Uninitialized = 0, /// A dummy mode in which no C++ inlining is enabled. - CIMK_None = 1, + CIMK_None, /// Refers to regular member function and operator calls. CIMK_MemberFunctions, @@ -102,8 +103,6 @@ enum CXXInlineableMemberKind { /// Describes the different modes of inter-procedural analysis. enum IPAKind { - IPAK_NotSet = 0, - /// Perform only intra-procedural analysis. IPAK_None = 1, @@ -121,6 +120,46 @@ enum IPAKind { IPAK_DynamicDispatchBifurcate = 5 }; +enum class ExplorationStrategyKind { + DFS, + BFS, + UnexploredFirst, + UnexploredFirstQueue, + UnexploredFirstLocationQueue, + BFSBlockDFSContents, +}; + +/// Describes the kinds for high-level analyzer mode. +enum UserModeKind { + /// Perform shallow but fast analyzes. + UMK_Shallow = 1, + + /// Perform deep analyzes. + UMK_Deep = 2 +}; + +/// Stores options for the analyzer from the command line. +/// +/// Some options are frontend flags (e.g.: -analyzer-output), but some are +/// analyzer configuration options, which are preceded by -analyzer-config +/// (e.g.: -analyzer-config notes-as-events=true). +/// +/// If you'd like to add a new frontend flag, add it to +/// include/clang/Driver/CC1Options.td, add a new field to store the value of +/// that flag in this class, and initialize it in +/// lib/Frontend/CompilerInvocation.cpp. +/// +/// If you'd like to add a new non-checker configuration, register it in +/// include/clang/StaticAnalyzer/Core/AnalyzerOptions.def, and refer to the +/// top of the file for documentation. +/// +/// If you'd like to add a new checker option, call getChecker*Option() +/// whenever. +/// +/// Some of the options are controlled by raw frontend flags for no good reason, +/// and should be eventually converted into -analyzer-config flags. New analyzer +/// options should not be implemented as frontend flags. Frontend flags still +/// make sense for things that do not affect the actual analysis. class AnalyzerOptions : public RefCountedBase<AnalyzerOptions> { public: using ConfigTable = llvm::StringMap<std::string>; @@ -132,6 +171,7 @@ public: std::vector<std::pair<std::string, bool>> CheckersControlList; /// A key-value table of use-specified configuration values. + // TODO: This shouldn't be public. ConfigTable Config; AnalysisStores AnalysisStoreOpt = RegionStoreModel; AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel; @@ -159,6 +199,8 @@ public: unsigned ShowCheckerHelp : 1; unsigned ShowEnabledCheckerList : 1; + unsigned ShowConfigOptionsList : 1; + unsigned ShouldEmitErrorsOnInvalidConfigValue : 1; unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; unsigned AnalyzeNestedBlocks : 1; @@ -181,190 +223,51 @@ public: /// The mode of function selection used during inlining. AnalysisInliningMode InliningMode = NoRedundancy; - enum class ExplorationStrategyKind { - DFS, - BFS, - UnexploredFirst, - UnexploredFirstQueue, - BFSBlockDFSContents, - NotSet - }; - -private: - ExplorationStrategyKind ExplorationStrategy = ExplorationStrategyKind::NotSet; - - /// Describes the kinds for high-level analyzer mode. - enum UserModeKind { - UMK_NotSet = 0, - - /// Perform shallow but fast analyzes. - UMK_Shallow = 1, - - /// Perform deep analyzes. - UMK_Deep = 2 - }; - - /// Controls the high-level analyzer mode, which influences the default - /// settings for some of the lower-level config options (such as IPAMode). - /// \sa getUserMode - UserModeKind UserMode = UMK_NotSet; - - /// Controls the mode of inter-procedural analysis. - IPAKind IPAMode = IPAK_NotSet; - - /// Controls which C++ member functions will be considered for inlining. - CXXInlineableMemberKind CXXMemberInliningMode; - - /// \sa includeImplicitDtorsInCFG - Optional<bool> IncludeImplicitDtorsInCFG; - - /// \sa includeTemporaryDtorsInCFG - Optional<bool> IncludeTemporaryDtorsInCFG; - - /// \sa IncludeLifetimeInCFG - Optional<bool> IncludeLifetimeInCFG; - - /// \sa IncludeLoopExitInCFG - Optional<bool> IncludeLoopExitInCFG; - - /// \sa IncludeRichConstructorsInCFG - Optional<bool> IncludeRichConstructorsInCFG; - - /// \sa mayInlineCXXStandardLibrary - Optional<bool> InlineCXXStandardLibrary; - - /// \sa includeScopesInCFG - Optional<bool> IncludeScopesInCFG; - - /// \sa mayInlineTemplateFunctions - Optional<bool> InlineTemplateFunctions; - - /// \sa mayInlineCXXAllocator - Optional<bool> InlineCXXAllocator; - - /// \sa mayInlineCXXContainerMethods - Optional<bool> InlineCXXContainerMethods; - - /// \sa mayInlineCXXSharedPtrDtor - Optional<bool> InlineCXXSharedPtrDtor; - - /// \sa mayInlineCXXTemporaryDtors - Optional<bool> InlineCXXTemporaryDtors; - - /// \sa mayInlineObjCMethod - Optional<bool> ObjCInliningMode; - - // Cache of the "ipa-always-inline-size" setting. - // \sa getAlwaysInlineSize - Optional<unsigned> AlwaysInlineSize; + // Create a field for each -analyzer-config option. +#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \ + SHALLOW_VAL, DEEP_VAL) \ + ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL) - /// \sa shouldSuppressNullReturnPaths - Optional<bool> SuppressNullReturnPaths; +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \ + TYPE NAME; - // \sa getMaxInlinableSize - Optional<unsigned> MaxInlinableSize; +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION +#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE - /// \sa shouldAvoidSuppressingNullArgumentPaths - Optional<bool> AvoidSuppressingNullArgumentPaths; + // Create an array of all -analyzer-config command line options. Sort it in + // the constructor. + std::vector<StringRef> AnalyzerConfigCmdFlags = { +#define ANALYZER_OPTION_DEPENDS_ON_USER_MODE(TYPE, NAME, CMDFLAG, DESC, \ + SHALLOW_VAL, DEEP_VAL) \ + ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, SHALLOW_VAL) - /// \sa shouldSuppressInlinedDefensiveChecks - Optional<bool> SuppressInlinedDefensiveChecks; +#define ANALYZER_OPTION(TYPE, NAME, CMDFLAG, DESC, DEFAULT_VAL) \ + CMDFLAG, - /// \sa shouldSuppressFromCXXStandardLibrary - Optional<bool> SuppressFromCXXStandardLibrary; - - /// \sa shouldCrosscheckWithZ3 - Optional<bool> CrosscheckWithZ3; - - /// \sa reportIssuesInMainSourceFile - Optional<bool> ReportIssuesInMainSourceFile; - - /// \sa StableReportFilename - Optional<bool> StableReportFilename; - - Optional<bool> SerializeStats; - - /// \sa getGraphTrimInterval - Optional<unsigned> GraphTrimInterval; - - /// \sa getMaxSymbolComplexity - Optional<unsigned> MaxSymbolComplexity; - - /// \sa getMaxTimesInlineLarge - Optional<unsigned> MaxTimesInlineLarge; - - /// \sa getMinCFGSizeTreatFunctionsAsLarge - Optional<unsigned> MinCFGSizeTreatFunctionsAsLarge; - - /// \sa getMaxNodesPerTopLevelFunction - Optional<unsigned> MaxNodesPerTopLevelFunction; - - /// \sa shouldInlineLambdas - Optional<bool> InlineLambdas; - - /// \sa shouldWidenLoops - Optional<bool> WidenLoops; - - /// \sa shouldUnrollLoops - Optional<bool> UnrollLoops; - - /// \sa shouldDisplayNotesAsEvents - Optional<bool> DisplayNotesAsEvents; - - /// \sa shouldAggressivelySimplifyBinaryOperation - Optional<bool> AggressiveBinaryOperationSimplification; - - /// \sa shouldEagerlyAssume - Optional<bool> EagerlyAssumeBinOpBifurcation; - - /// \sa getCTUDir - Optional<StringRef> CTUDir; - - /// \sa getCTUIndexName - Optional<StringRef> CTUIndexName; - - /// \sa naiveCTUEnabled - Optional<bool> NaiveCTU; +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.def" +#undef ANALYZER_OPTION +#undef ANALYZER_OPTION_DEPENDS_ON_USER_MODE + }; - /// \sa shouldElideConstructors - Optional<bool> ElideConstructors; + bool isUnknownAnalyzerConfig(StringRef Name) const { + assert(std::is_sorted(AnalyzerConfigCmdFlags.begin(), + AnalyzerConfigCmdFlags.end())); - /// 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); + return !std::binary_search(AnalyzerConfigCmdFlags.begin(), + AnalyzerConfigCmdFlags.end(), Name); + } -public: AnalyzerOptions() : DisableAllChecks(false), ShowCheckerHelp(false), - ShowEnabledCheckerList(false), AnalyzeAll(false), - AnalyzerDisplayProgress(false), AnalyzeNestedBlocks(false), - eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), - visualizeExplodedGraphWithGraphViz(false), - UnoptimizedCFG(false), - PrintStats(false), NoRetryExhausted(false), CXXMemberInliningMode() {} + ShowEnabledCheckerList(false), ShowConfigOptionsList(false), + AnalyzeAll(false), AnalyzerDisplayProgress(false), + AnalyzeNestedBlocks(false), eagerlyAssumeBinOpBifurcation(false), + TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), + UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false) { + llvm::sort(AnalyzerConfigCmdFlags); + } /// Interprets an option's string value as a boolean. The "true" string is /// interpreted as true and the "false" string is interpreted as false. @@ -373,34 +276,17 @@ public: /// @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 - /// depending on search mode). + /// @param [in] C The checker object the option belongs to. Checker options + /// are retrieved in the following format: + /// `-analyzer-config <package and checker name>:OptionName=Value. /// @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); + bool getCheckerBooleanOption(StringRef Name, bool DefaultVal, + const ento::CheckerBase *C, + bool SearchInParents = false) const; - /// Variant that accepts a Optional value to cache the result. - /// - /// @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 - /// depending 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. /// @@ -408,16 +294,16 @@ public: /// @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 - /// depending on search mode). + /// @param [in] C The checker object the option belongs to. Checker options + /// are retrieved in the following format: + /// `-analyzer-config <package and checker name>:OptionName=Value. /// @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); + int getCheckerIntegerOption(StringRef Name, int DefaultVal, + const ento::CheckerBase *C, + bool SearchInParents = false) const; /// Query an option's string value. /// @@ -425,26 +311,26 @@ public: /// @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 - /// depending on search mode). + /// @param [in] C The checker object the option belongs to. Checker options + /// are retrieved in the following format: + /// `-analyzer-config <package and checker name>:OptionName=Value. /// @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); + StringRef getCheckerStringOption(StringRef Name, StringRef DefaultVal, + const ento::CheckerBase *C, + bool SearchInParents = false) const; /// Retrieves and sets the UserMode. This is a high-level option, /// which is used to set other low-level options. It is not accessible /// outside of AnalyzerOptions. - UserModeKind getUserMode(); + UserModeKind getUserMode() const; - ExplorationStrategyKind getExplorationStrategy(); + ExplorationStrategyKind getExplorationStrategy() const; /// Returns the inter-procedural analysis mode. - IPAKind getIPAMode(); + IPAKind getIPAMode() const; /// Returns the option controlling which C++ member functions will be /// considered for inlining. @@ -452,286 +338,28 @@ public: /// This is controlled by the 'c++-inlining' config option. /// /// \sa CXXMemberInliningMode - bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K); - - /// Returns true if ObjectiveC inlining is enabled, false otherwise. - bool mayInlineObjCMethod(); - - /// Returns whether or not the destructors for C++ temporary objects should - /// be included in the CFG. - /// - /// This is controlled by the 'cfg-temporary-dtors' config option, which - /// accepts the values "true" and "false". - bool includeTemporaryDtorsInCFG(); - - /// Returns whether or not implicit destructors for C++ objects should - /// be included in the CFG. - /// - /// This is controlled by the 'cfg-implicit-dtors' config option, which - /// accepts the values "true" and "false". - bool includeImplicitDtorsInCFG(); - - /// Returns whether or not end-of-lifetime information should be included in - /// the CFG. - /// - /// This is controlled by the 'cfg-lifetime' config option, which accepts - /// the values "true" and "false". - bool includeLifetimeInCFG(); - - /// Returns whether or not the end of the loop information should be included - /// in the CFG. - /// - /// This is controlled by the 'cfg-loopexit' config option, which accepts - /// the values "true" and "false". - bool includeLoopExitInCFG(); - - /// Returns whether or not construction site information should be included - /// in the CFG C++ constructor elements. - /// - /// This is controlled by the 'cfg-rich-constructors' config options, - /// which accepts the values "true" and "false". - bool includeRichConstructorsInCFG(); - - /// Returns whether or not scope information should be included in the CFG. - /// - /// This is controlled by the 'cfg-scope-info' config option, which accepts - /// the values "true" and "false". - bool includeScopesInCFG(); - - /// Returns whether or not C++ standard library functions may be considered - /// for inlining. - /// - /// This is controlled by the 'c++-stdlib-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXStandardLibrary(); - - /// Returns whether or not templated functions may be considered for inlining. - /// - /// This is controlled by the 'c++-template-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineTemplateFunctions(); - - /// Returns whether or not allocator call may be considered for inlining. - /// - /// This is controlled by the 'c++-allocator-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXAllocator(); - - /// Returns whether or not methods of C++ container objects may be considered - /// for inlining. - /// - /// This is controlled by the 'c++-container-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXContainerMethods(); - - /// Returns whether or not the destructor of C++ 'shared_ptr' may be - /// considered for inlining. - /// - /// This covers std::shared_ptr, std::tr1::shared_ptr, and boost::shared_ptr, - /// and indeed any destructor named "~shared_ptr". - /// - /// This is controlled by the 'c++-shared_ptr-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXSharedPtrDtor(); - - /// Returns true if C++ temporary destructors should be inlined during - /// analysis. - /// - /// If temporary destructors are disabled in the CFG via the - /// 'cfg-temporary-dtors' option, temporary destructors would not be - /// inlined anyway. - /// - /// This is controlled by the 'c++-temp-dtor-inlining' config option, which - /// accepts the values "true" and "false". - bool mayInlineCXXTemporaryDtors(); - - /// Returns whether or not paths that go through null returns should be - /// suppressed. - /// - /// This is a heuristic for avoiding bug reports with paths that go through - /// inlined functions that are more defensive than their callers. - /// - /// This is controlled by the 'suppress-null-return-paths' config option, - /// which accepts the values "true" and "false". - bool shouldSuppressNullReturnPaths(); - - /// Returns whether a bug report should \em not be suppressed if its path - /// includes a call with a null argument, even if that call has a null return. - /// - /// This option has no effect when #shouldSuppressNullReturnPaths() is false. - /// - /// This is a counter-heuristic to avoid false negatives. - /// - /// This is controlled by the 'avoid-suppressing-null-argument-paths' config - /// option, which accepts the values "true" and "false". - bool shouldAvoidSuppressingNullArgumentPaths(); - - /// Returns whether or not diagnostics containing inlined defensive NULL - /// checks should be suppressed. - /// - /// This is controlled by the 'suppress-inlined-defensive-checks' config - /// option, which accepts the values "true" and "false". - bool shouldSuppressInlinedDefensiveChecks(); - - /// Returns whether or not diagnostics reported within the C++ standard - /// library should be suppressed. - /// - /// This is controlled by the 'suppress-c++-stdlib' config option, - /// which accepts the values "true" and "false". - bool shouldSuppressFromCXXStandardLibrary(); - - /// Returns whether bug reports should be crosschecked with the Z3 - /// constraint manager backend. - /// - /// This is controlled by the 'crosscheck-with-z3' config option, - /// which accepts the values "true" and "false". - bool shouldCrosscheckWithZ3(); - - /// Returns whether or not the diagnostic report should be always reported - /// in the main source file and not the headers. - /// - /// This is controlled by the 'report-in-main-source-file' config option, - /// which accepts the values "true" and "false". - bool shouldReportIssuesInMainSourceFile(); - - /// Returns whether or not the report filename should be random or not. - /// - /// This is controlled by the 'stable-report-filename' config option, - /// which accepts the values "true" and "false". Default = false - bool shouldWriteStableReportFilename(); - - /// \return Whether the analyzer should - /// serialize statistics to plist output. - /// Statistics would be serialized in JSON format inside the main dictionary - /// under the \c statistics key. - /// Available only if compiled in assert mode or with LLVM statistics - /// explicitly enabled. - bool shouldSerializeStats(); - - /// Returns whether irrelevant parts of a bug report path should be pruned - /// out of the final output. - /// - /// This is controlled by the 'prune-paths' config option, which accepts the - /// values "true" and "false". - bool shouldPrunePaths(); - - /// Returns true if 'static' initializers should be in conditional logic - /// in the CFG. - bool shouldConditionalizeStaticInitializers(); - - // Returns the size of the functions (in basic blocks), which should be - // considered to be small enough to always inline. - // - // This is controlled by "ipa-always-inline-size" analyzer-config option. - unsigned getAlwaysInlineSize(); - - // Returns the bound on the number of basic blocks in an inlined function - // (50 by default). - // - // This is controlled by "-analyzer-config max-inlinable-size" option. - unsigned getMaxInlinableSize(); - - /// Returns true if the analyzer engine should synthesize fake bodies - /// for well-known functions. - bool shouldSynthesizeBodies(); - - /// Returns how often nodes in the ExplodedGraph should be recycled to save - /// memory. - /// - /// This is controlled by the 'graph-trim-interval' config option. To disable - /// node reclamation, set the option to "0". - unsigned getGraphTrimInterval(); - - /// Returns the maximum complexity of symbolic constraint (50 by default). - /// - /// This is controlled by "-analyzer-config max-symbol-complexity" option. - unsigned getMaxSymbolComplexity(); - - /// Returns the maximum times a large function could be inlined. - /// - /// This is controlled by the 'max-times-inline-large' config option. - unsigned getMaxTimesInlineLarge(); - - /// Returns the number of basic blocks a function needs to have to be - /// considered large for the 'max-times-inline-large' config option. - /// - /// This is controlled by the 'min-cfg-size-treat-functions-as-large' config - /// option. - unsigned getMinCFGSizeTreatFunctionsAsLarge(); - - /// Returns the maximum number of nodes the analyzer can generate while - /// exploring a top level function (for each exploded graph). - /// 150000 is default; 0 means no limit. - /// - /// This is controlled by the 'max-nodes' config option. - unsigned getMaxNodesPerTopLevelFunction(); - - /// Returns true if lambdas should be inlined. Otherwise a sink node will be - /// generated each time a LambdaExpr is visited. - bool shouldInlineLambdas(); - - /// Returns true if the analysis should try to widen loops. - /// This is controlled by the 'widen-loops' config option. - bool shouldWidenLoops(); - - /// Returns true if the analysis should try to unroll loops with known bounds. - /// This is controlled by the 'unroll-loops' config option. - bool shouldUnrollLoops(); - - /// Returns true if the bug reporter should transparently treat extra note - /// diagnostic pieces as event diagnostic pieces. Useful when the diagnostic - /// consumer doesn't support the extra note pieces. - /// - /// This is controlled by the 'extra-notes-as-events' option, which defaults - /// to false when unset. - bool shouldDisplayNotesAsEvents(); - - /// Returns true if SValBuilder should rearrange comparisons and additive - /// operations of symbolic expressions which consist of a sum of a symbol and - /// a concrete integer into the format where symbols are on the left-hand - /// side and the integer is on the right. This is only done if both symbols - /// and both concrete integers are signed, greater than or equal to the - /// quarter of the minimum value of the type and less than or equal to the - /// quarter of the maximum value of that type. - /// - /// A + n <OP> B + m becomes A - B <OP> m - n, where A and B symbolic, - /// n and m are integers. <OP> is any of '==', '!=', '<', '<=', '>', '>=', - /// '+' or '-'. The rearrangement also happens with '-' instead of '+' on - // either or both side and also if any or both integers are missing. - bool shouldAggressivelySimplifyBinaryOperation(); - - /// Returns true if we should eagerly assume evaluations of - /// conditionals, thus, bifurcating the path. - /// - /// This indicates how the engine should handle expressions such as: 'x = - /// (y != 0)'. When this is true then the subexpression 'y != 0' will be - /// eagerly assumed to be true or false, thus evaluating it to the integers 0 - /// or 1 respectively. The upside is that this can increase analysis - /// precision until we have a better way to lazily evaluate such logic. The - /// downside is that it eagerly bifurcates paths. - bool shouldEagerlyAssume(); - - /// Returns the directory containing the CTU related files. - StringRef getCTUDir(); - - /// Returns the name of the file containing the CTU index of functions. - StringRef getCTUIndexName(); - - /// Returns true when naive cross translation unit analysis is enabled. - /// This is an experimental feature to inline functions from another - /// translation units. - bool naiveCTUEnabled(); - - /// Returns true if elidable C++ copy-constructors and move-constructors - /// should be actually elided during analysis. Both behaviors are allowed - /// by the C++ standard, and the analyzer, like CodeGen, defaults to eliding. - /// Starting with C++17 some elisions become mandatory, and in these cases - /// the option will be ignored. - bool shouldElideConstructors(); + bool mayInlineCXXMemberFunction(CXXInlineableMemberKind K) const; }; using AnalyzerOptionsRef = IntrusiveRefCntPtr<AnalyzerOptions>; +//===----------------------------------------------------------------------===// +// We'll use AnalyzerOptions in the frontend, but we can't link the frontend +// with clangStaticAnalyzerCore, because clangStaticAnalyzerCore depends on +// clangFrontend. +// +// For this reason, implement some methods in this header file. +//===----------------------------------------------------------------------===// + +inline UserModeKind AnalyzerOptions::getUserMode() const { + auto K = llvm::StringSwitch<llvm::Optional<UserModeKind>>(UserMode) + .Case("shallow", UMK_Shallow) + .Case("deep", UMK_Deep) + .Default(None); + assert(K.hasValue() && "User mode is invalid."); + return K.getValue(); +} + } // namespace clang #endif // LLVM_CLANG_STATICANALYZER_CORE_ANALYZEROPTIONS_H diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h index ee16522c0b..c023ed5641 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -345,12 +345,11 @@ public: namespace bugreporter { -/// Attempts to add visitors to trace a null or undefined value back to its -/// point of origin, whether it is a symbol constrained to null or an explicit -/// assignment. +/// Attempts to add visitors to track expression value back to its point of +/// origin. /// /// \param N A node "downstream" from the evaluation of the statement. -/// \param S The statement whose value is null or undefined. +/// \param E The expression value which we are tracking /// \param R The bug report to which visitors should be attached. /// \param EnableNullFPSuppression Whether we should employ false positive /// suppression (inlined defensive checks, returned null). @@ -358,13 +357,10 @@ namespace bugreporter { /// \return Whether or not the function was able to add visitors for this /// statement. Note that returning \c true does not actually imply /// that any visitors were added. -bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, - bool EnableNullFPSuppression = true); +bool trackExpressionValue(const ExplodedNode *N, const Expr *E, BugReport &R, + bool EnableNullFPSuppression = true); const Expr *getDerefExpr(const Stmt *S); -const Stmt *GetDenomExpr(const ExplodedNode *N); -const Stmt *GetRetValExpr(const ExplodedNode *N); -bool isDeclRefExprToReference(const Expr *E); } // namespace bugreporter diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h index 7fff42903b..e9c682d798 100644 --- a/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h +++ b/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h @@ -118,7 +118,7 @@ public: /// Only runs visitors, no output generated. None, - /// Used for HTML and text output. + /// Used for HTML, SARIF, and text output. Minimal, /// Used for plist output, used for "arrows" generation. diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 8484cfe4c9..786465cee8 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -558,6 +558,8 @@ struct ImplicitNullDerefEvent { // dereference might happen later (for example pointer passed to a parameter // that is marked with nonnull attribute.) bool IsDirectDereference; + + static int Tag; }; /// A helper class which wraps a boolean value set to false by default. diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 463c842ec5..538ed19f7e 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -532,19 +532,19 @@ public: template <typename EVENT> void _registerListenerForEvent(CheckEventFunc checkfn) { - EventInfo &info = Events[getTag<EVENT>()]; + EventInfo &info = Events[&EVENT::Tag]; info.Checkers.push_back(checkfn); } template <typename EVENT> void _registerDispatcherForEvent() { - EventInfo &info = Events[getTag<EVENT>()]; + EventInfo &info = Events[&EVENT::Tag]; info.HasDispatcher = true; } template <typename EVENT> void _dispatchEvent(const EVENT &event) const { - EventsTy::const_iterator I = Events.find(getTag<EVENT>()); + EventsTy::const_iterator I = Events.find(&EVENT::Tag); if (I == Events.end()) return; const EventInfo &info = I->second; diff --git a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h b/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h deleted file mode 100644 index 2d13bf34cd..0000000000 --- a/include/clang/StaticAnalyzer/Core/CheckerOptInfo.h +++ /dev/null @@ -1,44 +0,0 @@ -//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H -#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H - -#include "clang/Basic/LLVM.h" -#include "llvm/ADT/StringRef.h" - -namespace clang { -namespace ento { - -/// Represents a request to include or exclude a checker or package from a -/// specific analysis run. -/// -/// \sa CheckerRegistry::initializeManager -class CheckerOptInfo { - StringRef Name; - bool Enable; - bool Claimed; - -public: - CheckerOptInfo(StringRef name, bool enable) - : Name(name), Enable(enable), Claimed(false) { } - - StringRef getName() const { return Name; } - bool isEnabled() const { return Enable; } - bool isDisabled() const { return !isEnabled(); } - - bool isClaimed() const { return Claimed; } - bool isUnclaimed() const { return !isClaimed(); } - void claim() { Claimed = true; } -}; - -} // end namespace ento -} // end namespace clang - -#endif diff --git a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h index d580dda734..740754090d 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerRegistry.h +++ b/include/clang/StaticAnalyzer/Core/CheckerRegistry.h @@ -73,8 +73,6 @@ class DiagnosticsEngine; namespace ento { -class CheckerOptInfo; - /// Manages a set of available checkers for running a static analysis. /// The checkers are organized into packages by full name, where including /// a package will recursively include all subpackages and checkers within it. @@ -123,8 +121,8 @@ public: /// all checkers specified by the given CheckerOptInfo list. The order of this /// list is significant; later options can be used to reverse earlier ones. /// This can be used to exclude certain checkers in an included package. - void initializeManager(CheckerManager &mgr, - SmallVectorImpl<CheckerOptInfo> &opts) const; + void initializeManager(CheckerManager &mgr, const AnalyzerOptions &Opts, + DiagnosticsEngine &diags) const; /// Check if every option corresponds to a specific checker or package. void validateCheckerOptions(const AnalyzerOptions &opts, @@ -133,8 +131,7 @@ public: /// Prints the name and description of all checkers in this registry. /// This output is not intended to be machine-parseable. void printHelp(raw_ostream &out, size_t maxNameChars = 30) const; - void printList(raw_ostream &out, - SmallVectorImpl<CheckerOptInfo> &opts) const; + void printList(raw_ostream &out, const AnalyzerOptions &opts) const; private: mutable CheckerInfoList Checkers; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 4c50eafbde..a53e8ee693 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -921,15 +921,30 @@ public: return getOriginExpr()->getOperatorNew(); } + /// Number of non-placement arguments to the call. It is equal to 2 for + /// C++17 aligned operator new() calls that have alignment implicitly + /// passed as the second argument, and to 1 for other operator new() calls. + unsigned getNumImplicitArgs() const { + return getOriginExpr()->passAlignment() ? 2 : 1; + } + unsigned getNumArgs() const override { - return getOriginExpr()->getNumPlacementArgs() + 1; + return getOriginExpr()->getNumPlacementArgs() + getNumImplicitArgs(); } const Expr *getArgExpr(unsigned Index) const override { // The first argument of an allocator call is the size of the allocation. - if (Index == 0) + if (Index < getNumImplicitArgs()) return nullptr; - return getOriginExpr()->getPlacementArg(Index - 1); + return getOriginExpr()->getPlacementArg(Index - getNumImplicitArgs()); + } + + /// Number of placement arguments to the operator new() call. For example, + /// standard std::nothrow operator new and standard placement new both have + /// 1 implicit argument (size) and 1 placement argument, while regular + /// operator new() has 1 implicit argument and 0 placement arguments. + const Expr *getPlacementArgExpr(unsigned Index) const { + return getOriginExpr()->getPlacementArg(Index); } Kind getKind() const override { return CE_CXXAllocator; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h index 2f8ead0746..b0d514dc28 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h @@ -36,10 +36,7 @@ using DynamicTypeMapImpl = template <> struct ProgramStateTrait<DynamicTypeMap> : public ProgramStatePartialTrait<DynamicTypeMapImpl> { - static void *GDMIndex() { - static int index = 0; - return &index; - } + static void *GDMIndex(); }; /// Get dynamic type information for a region. diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h index cf4164dcd2..bf460df278 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h @@ -210,10 +210,14 @@ public: return const_cast<ExplodedNode*>(this)->getFirstPred(); } - const ExplodedNode *getFirstSucc() const { + ExplodedNode *getFirstSucc() { return succ_empty() ? nullptr : *(succ_begin()); } + const ExplodedNode *getFirstSucc() const { + return const_cast<ExplodedNode*>(this)->getFirstSucc(); + } + // Iterators over successor and predecessor vertices. using succ_iterator = ExplodedNode * const *; using const_succ_iterator = const ExplodedNode * const *; @@ -243,8 +247,10 @@ public: int64_t getID(ExplodedGraph *G) const; /// The node is trivial if it has only one successor, only one predecessor, + /// it's predecessor has only one successor, /// and its program state is the same as the program state of the previous /// node. + /// Trivial nodes may be skipped while printing exploded graph. bool isTrivial() const; private: @@ -460,7 +466,6 @@ public: // GraphTraits namespace llvm { - template <> struct GraphTraits<clang::ento::ExplodedGraph *> { using GraphTy = clang::ento::ExplodedGraph *; using NodeRef = clang::ento::ExplodedNode *; @@ -471,17 +476,19 @@ namespace llvm { return *G->roots_begin(); } + static bool predecessorOfTrivial(NodeRef N) { + return N->succ_size() == 1 && N->getFirstSucc()->isTrivial(); + } + static ChildIteratorType child_begin(NodeRef N) { - if (N->succ_size() == 1 && (*N->succ_begin())->isTrivial()) { + if (predecessorOfTrivial(N)) return child_begin(*N->succ_begin()); - } return N->succ_begin(); } static ChildIteratorType child_end(NodeRef N) { - if (N->succ_size() == 1 && (*N->succ_begin())->isTrivial()) { - return child_end(*N->succ_begin()); - } + if (predecessorOfTrivial(N)) + return child_end(N->getFirstSucc()); return N->succ_end(); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 91e47b37b7..86b776afb8 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -832,7 +832,7 @@ struct ReplayWithoutInlining{}; template <> struct ProgramStateTrait<ReplayWithoutInlining> : public ProgramStatePartialTrait<const void*> { - static void *GDMIndex() { static int index = 0; return &index; } + static void *GDMIndex(); }; } // namespace ento diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h index 0b0e32b8e3..bf01289a40 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -118,6 +118,10 @@ public: const MemRegion *getBaseRegion() const; + /// Recursively retrieve the region of the most derived class instance of + /// regions of C++ base class instances. + const MemRegion *getMostDerivedObjectRegion() const; + /// Check if the region is a subregion of the given region. /// Each region is a subregion of itself. virtual bool isSubRegionOf(const MemRegion *R) const; @@ -1077,7 +1081,7 @@ public: void dump() const; }; -/// ElementRegin is used to represent both array elements and casts. +/// ElementRegion is used to represent both array elements and casts. class ElementRegion : public TypedValueRegion { friend class MemRegionManager; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index 13f5b14378..f544204497 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -348,6 +348,8 @@ public: /// a value of such type. SVal getSValAsScalarOrLoc(const MemRegion *R) const; + using region_iterator = const MemRegion **; + /// Visits the symbols reachable from the given SVal using the provided /// SymbolVisitor. /// @@ -357,24 +359,14 @@ public: /// \sa ScanReachableSymbols bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const; - /// Visits the symbols reachable from the SVals in the given range - /// using the provided SymbolVisitor. - bool scanReachableSymbols(const SVal *I, const SVal *E, - SymbolVisitor &visitor) const; - /// Visits the symbols reachable from the regions in the given /// MemRegions range using the provided SymbolVisitor. - bool scanReachableSymbols(const MemRegion * const *I, - const MemRegion * const *E, + bool scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable, SymbolVisitor &visitor) const; template <typename CB> CB scanReachableSymbols(SVal val) const; - template <typename CB> CB scanReachableSymbols(const SVal *beg, - const SVal *end) const; - template <typename CB> CB - scanReachableSymbols(const MemRegion * const *beg, - const MemRegion * const *end) const; + scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable) const; /// Create a new state in which the statement is marked as tainted. LLVM_NODISCARD ProgramStateRef @@ -883,17 +875,10 @@ CB ProgramState::scanReachableSymbols(SVal val) const { } template <typename CB> -CB ProgramState::scanReachableSymbols(const SVal *beg, const SVal *end) const { - CB cb(this); - scanReachableSymbols(beg, end, cb); - return cb; -} - -template <typename CB> -CB ProgramState::scanReachableSymbols(const MemRegion * const *beg, - const MemRegion * const *end) const { +CB ProgramState::scanReachableSymbols( + llvm::iterator_range<region_iterator> Reachable) const { CB cb(this); - scanReachableSymbols(beg, end, cb); + scanReachableSymbols(Reachable, cb); return cb; } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h index d2ba1f7c95..1b12a4edc2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h @@ -131,7 +131,7 @@ using ConstraintRangeTy = llvm::ImmutableMap<SymbolRef, RangeSet>; template <> struct ProgramStateTrait<ConstraintRange> : public ProgramStatePartialTrait<ConstraintRangeTy> { - static void *GDMIndex() { static int Index; return &Index; } + static void *GDMIndex(); }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h index 1a645cb870..8eaa9365be 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -134,9 +134,9 @@ public: // A value has been obtained, check if it is the only value SMTExprRef NotExp = SMTConv::fromBinOp( Solver, Exp, BO_NE, - Ty->isBooleanType() ? Solver->fromBoolean(Value.getBoolValue()) - : Solver->fromAPSInt(Value), - false); + Ty->isBooleanType() ? Solver->mkBoolean(Value.getBoolValue()) + : Solver->mkBitvector(Value, Value.getBitWidth()), + /*isSigned=*/false); Solver->addConstraint(NotExp); @@ -198,7 +198,7 @@ public: auto &CZFactory = State->get_context<ConstraintSMT>(); for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) { - if (SymReaper.maybeDead(I->first)) + if (SymReaper.isDead(I->first)) CZ = CZFactory.remove(CZ, *I); } @@ -218,6 +218,52 @@ public: OS << nl; } + bool canReasonAbout(SVal X) const override { + const TargetInfo &TI = getBasicVals().getContext().getTargetInfo(); + + Optional<nonloc::SymbolVal> SymVal = X.getAs<nonloc::SymbolVal>(); + if (!SymVal) + return true; + + const SymExpr *Sym = SymVal->getSymbol(); + QualType Ty = Sym->getType(); + + // Complex types are not modeled + if (Ty->isComplexType() || Ty->isComplexIntegerType()) + return false; + + // Non-IEEE 754 floating-point types are not modeled + if ((Ty->isSpecificBuiltinType(BuiltinType::LongDouble) && + (&TI.getLongDoubleFormat() == &llvm::APFloat::x87DoubleExtended() || + &TI.getLongDoubleFormat() == &llvm::APFloat::PPCDoubleDouble()))) + return false; + + if (Ty->isRealFloatingType()) + return Solver->isFPSupported(); + + if (isa<SymbolData>(Sym)) + return true; + + SValBuilder &SVB = getSValBuilder(); + + if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) + return canReasonAbout(SVB.makeSymbolVal(SC->getOperand())); + + if (const BinarySymExpr *BSE = dyn_cast<BinarySymExpr>(Sym)) { + if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(BSE)) + return canReasonAbout(SVB.makeSymbolVal(SIE->getLHS())); + + if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) + return canReasonAbout(SVB.makeSymbolVal(ISE->getRHS())); + + if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(BSE)) + return canReasonAbout(SVB.makeSymbolVal(SSE->getLHS())) && + canReasonAbout(SVB.makeSymbolVal(SSE->getRHS())); + } + + llvm_unreachable("Unsupported expression to reason about!"); + } + /// Dumps SMT formula LLVM_DUMP_METHOD void dump() const { Solver->dump(); } diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h index 8be7d4c467..cdca2a0970 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h @@ -246,7 +246,7 @@ public: // Logical operators case BO_LAnd: case BO_LOr: - return fromBinOp(Solver, LHS, Op, RHS, false); + return fromBinOp(Solver, LHS, Op, RHS, /*isSigned=*/false); default:; } @@ -294,14 +294,14 @@ public: if (FromTy->isIntegralOrEnumerationType() && ToTy->isRealFloatingType()) { SMTSortRef Sort = Solver->getFloatSort(ToBitWidth); return FromTy->isSignedIntegerOrEnumerationType() - ? Solver->mkFPtoSBV(Exp, Sort) - : Solver->mkFPtoUBV(Exp, Sort); + ? Solver->mkSBVtoFP(Exp, Sort) + : Solver->mkUBVtoFP(Exp, Sort); } if (FromTy->isRealFloatingType() && ToTy->isIntegralOrEnumerationType()) return ToTy->isSignedIntegerOrEnumerationType() - ? Solver->mkSBVtoFP(Exp, ToBitWidth) - : Solver->mkUBVtoFP(Exp, ToBitWidth); + ? Solver->mkFPtoSBV(Exp, ToBitWidth) + : Solver->mkFPtoUBV(Exp, ToBitWidth); llvm_unreachable("Unsupported explicit type cast!"); } @@ -379,14 +379,14 @@ public: getSymExpr(Solver, Ctx, SIE->getLHS(), <y, hasComparison); llvm::APSInt NewRInt; std::tie(NewRInt, RTy) = fixAPSInt(Ctx, SIE->getRHS()); - SMTExprRef RHS = Solver->fromAPSInt(NewRInt); + SMTExprRef RHS = Solver->mkBitvector(NewRInt, NewRInt.getBitWidth()); return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy); } if (const IntSymExpr *ISE = dyn_cast<IntSymExpr>(BSE)) { llvm::APSInt NewLInt; std::tie(NewLInt, LTy) = fixAPSInt(Ctx, ISE->getLHS()); - SMTExprRef LHS = Solver->fromAPSInt(NewLInt); + SMTExprRef LHS = Solver->mkBitvector(NewLInt, NewLInt.getBitWidth()); SMTExprRef RHS = getSymExpr(Solver, Ctx, ISE->getRHS(), &RTy, hasComparison); return getBinExpr(Solver, Ctx, LHS, LTy, Op, RHS, RTy, RetTy); @@ -466,7 +466,7 @@ public: llvm::APFloat Zero = llvm::APFloat::getZero(Ctx.getFloatTypeSemantics(Ty)); return fromFloatBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE, - Solver->fromAPFloat(Zero)); + Solver->mkFloat(Zero)); } if (Ty->isIntegralOrEnumerationType() || Ty->isAnyPointerType() || @@ -477,8 +477,10 @@ public: if (Ty->isBooleanType()) return Assumption ? fromUnOp(Solver, UO_LNot, Exp) : Exp; - return fromBinOp(Solver, Exp, Assumption ? BO_EQ : BO_NE, - Solver->fromInt("0", Ctx.getTypeSize(Ty)), isSigned); + return fromBinOp( + Solver, Exp, Assumption ? BO_EQ : BO_NE, + Solver->mkBitvector(llvm::APSInt("0"), Ctx.getTypeSize(Ty)), + isSigned); } llvm_unreachable("Unsupported type for zero value!"); @@ -493,7 +495,8 @@ public: QualType FromTy; llvm::APSInt NewFromInt; std::tie(NewFromInt, FromTy) = fixAPSInt(Ctx, From); - SMTExprRef FromExp = Solver->fromAPSInt(NewFromInt); + SMTExprRef FromExp = + Solver->mkBitvector(NewFromInt, NewFromInt.getBitWidth()); // Convert symbol QualType SymTy; @@ -507,7 +510,7 @@ public: QualType ToTy; llvm::APSInt NewToInt; std::tie(NewToInt, ToTy) = fixAPSInt(Ctx, To); - SMTExprRef ToExp = Solver->fromAPSInt(NewToInt); + SMTExprRef ToExp = Solver->mkBitvector(NewToInt, NewToInt.getBitWidth()); assert(FromTy == ToTy && "Range values have different types!"); // Construct two (in)equalities, and a logical and/or diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h index 71bfb400fc..2abe5fc987 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SMTSolver.h @@ -226,23 +226,23 @@ public: /// operation virtual SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) = 0; - /// Creates a floating-point conversion from floatint-point to signed - /// bitvector operation - virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, - const SMTSortRef &To) = 0; - - /// Creates a floating-point conversion from floatint-point to unsigned - /// bitvector operation - virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, - const SMTSortRef &To) = 0; - /// Creates a floating-point conversion from signed bitvector to /// floatint-point operation - virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From, unsigned ToWidth) = 0; + virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From, + const SMTSortRef &To) = 0; /// Creates a floating-point conversion from unsigned bitvector to /// floatint-point operation - virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From, unsigned ToWidth) = 0; + virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From, + const SMTSortRef &To) = 0; + + /// Creates a floating-point conversion from floatint-point to signed + /// bitvector operation + virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) = 0; + + /// Creates a floating-point conversion from floatint-point to unsigned + /// bitvector operation + virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) = 0; /// Creates a new symbol, given a name and a sort virtual SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) = 0; @@ -273,18 +273,6 @@ public: virtual bool getInterpretation(const SMTExprRef &Exp, llvm::APFloat &Float) = 0; - /// Construct an SMTExprRef value from a boolean. - virtual SMTExprRef fromBoolean(const bool Bool) = 0; - - /// Construct an SMTExprRef value from a finite APFloat. - virtual SMTExprRef fromAPFloat(const llvm::APFloat &Float) = 0; - - /// Construct an SMTExprRef value from an APSInt. - virtual SMTExprRef fromAPSInt(const llvm::APSInt &Int) = 0; - - /// Construct an SMTExprRef value from an integer. - virtual SMTExprRef fromInt(const char *Int, uint64_t BitWidth) = 0; - /// Check if the constraints are satisfiable virtual Optional<bool> check() const = 0; @@ -295,7 +283,10 @@ public: virtual void pop(unsigned NumStates = 1) = 0; /// Reset the solver and remove all constraints. - virtual void reset() const = 0; + virtual void reset() = 0; + + /// Checks if the solver supports floating-points. + virtual bool isFPSupported() = 0; virtual void print(raw_ostream &OS) const = 0; }; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index 4ab7161459..f49f761c77 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -260,12 +260,12 @@ public: public: virtual ~BindingsHandler(); + /// \return whether the iteration should continue. virtual bool HandleBinding(StoreManager& SMgr, Store store, const MemRegion *region, SVal val) = 0; }; - class FindUniqueBinding : - public BindingsHandler { + class FindUniqueBinding : public BindingsHandler { SymbolRef Sym; const MemRegion* Binding = nullptr; bool First = true; diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h index b014c63709..d02a8abd11 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h @@ -558,7 +558,6 @@ class SymbolReaper { SymbolMapTy TheLiving; SymbolSetTy MetadataInUse; - SymbolSetTy TheDead; RegionSetTy RegionRoots; @@ -603,21 +602,6 @@ public: /// symbol marking has occurred, i.e. in the MarkLiveSymbols callback. void markInUse(SymbolRef sym); - /// If a symbol is known to be live, marks the symbol as live. - /// - /// Otherwise, if the symbol cannot be proven live, it is marked as dead. - /// Returns true if the symbol is dead, false if live. - bool maybeDead(SymbolRef sym); - - using dead_iterator = SymbolSetTy::const_iterator; - - dead_iterator dead_begin() const { return TheDead.begin(); } - dead_iterator dead_end() const { return TheDead.end(); } - - bool hasDeadSymbols() const { - return !TheDead.empty(); - } - using region_iterator = RegionSetTy::const_iterator; region_iterator region_begin() const { return RegionRoots.begin(); } @@ -626,9 +610,9 @@ public: /// Returns whether or not a symbol has been confirmed dead. /// /// This should only be called once all marking of dead symbols has completed. - /// (For checkers, this means only in the evalDeadSymbols callback.) - bool isDead(SymbolRef sym) const { - return TheDead.count(sym); + /// (For checkers, this means only in the checkDeadSymbols callback.) + bool isDead(SymbolRef sym) { + return !isLive(sym); } void markLive(const MemRegion *region); diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h index ce19b7131d..8218fb1eea 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/TaintManager.h @@ -34,10 +34,7 @@ using TaintMapImpl = llvm::ImmutableMap<SymbolRef, TaintTagType>; template<> struct ProgramStateTrait<TaintMap> : public ProgramStatePartialTrait<TaintMapImpl> { - static void *GDMIndex() { - static int index = 0; - return &index; - } + static void *GDMIndex(); }; /// The GDM component mapping derived symbols' parent symbols to their @@ -49,10 +46,7 @@ using DerivedSymTaintImpl = llvm::ImmutableMap<SymbolRef, TaintedSubRegions>; template<> struct ProgramStateTrait<DerivedSymTaint> : public ProgramStatePartialTrait<DerivedSymTaintImpl> { - static void *GDMIndex() { - static int index; - return &index; - } + static void *GDMIndex(); }; class TaintManager { diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h index 07edd35ff9..ef3c2694b2 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h @@ -85,6 +85,7 @@ public: static std::unique_ptr<WorkList> makeBFSBlockDFSContents(); static std::unique_ptr<WorkList> makeUnexploredFirst(); static std::unique_ptr<WorkList> makeUnexploredFirstPriorityQueue(); + static std::unique_ptr<WorkList> makeUnexploredFirstPriorityLocationQueue(); }; } // end ento namespace diff --git a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h index fc506ae52e..de16a1781a 100644 --- a/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h +++ b/include/clang/StaticAnalyzer/Core/RetainSummaryManager.h @@ -56,7 +56,7 @@ enum ArgEffect { /// The argument has its reference count decreased by 1. This is as /// if a -release message has been sent to the argument. This differs - /// in behavior from DecRef when GC is enabled. + /// in behavior from DecRef when ARC is enabled. DecRefMsg, /// The argument has its reference count decreased by 1 to model @@ -65,7 +65,7 @@ enum ArgEffect { /// The argument has its reference count increased by 1. This is as /// if a -retain message has been sent to the argument. This differs - /// in behavior from IncRef when GC is enabled. + /// in behavior from IncRef when ARC is enabled. IncRefMsg, /// The argument has its reference count increased by 1. This is as @@ -139,7 +139,7 @@ public: OwnedWhenTrackedReceiver, // Treat this function as returning a non-tracked symbol even if // the function has been inlined. This is used where the call - // site summary is more presise than the summary indirectly produced + // site summary is more precise than the summary indirectly produced // by inlining the function NoRetHard }; @@ -369,8 +369,12 @@ public: /// This is only meaningful if the summary applies to an ObjCMessageExpr*. ArgEffect getReceiverEffect() const { return Receiver; } + /// \return the effect on the "this" receiver of the method call. ArgEffect getThisEffect() const { return This; } + /// Set the effect of the method on "this". + void setThisEffect(ArgEffect e) { This = e; } + bool isNoop() const { return Ret == RetEffect::MakeNoRet() && Receiver == DoNothing && DefaultArgEffect == MayEscape && This == DoNothing @@ -465,6 +469,8 @@ public: } }; +class RetainSummaryTemplate; + class RetainSummaryManager { typedef llvm::DenseMap<const FunctionDecl*, const RetainSummary *> FuncSummariesTy; @@ -479,7 +485,10 @@ class RetainSummaryManager { /// Records whether or not the analyzed code runs in ARC mode. const bool ARCEnabled; - /// Track sublcasses of OSObject + /// Track Objective-C and CoreFoundation objects. + const bool TrackObjCAndCFObjects; + + /// Track sublcasses of OSObject. const bool TrackOSObjects; /// FuncSummaries - A map from FunctionDecls to summaries. @@ -530,6 +539,8 @@ class RetainSummaryManager { /// Decrement the reference count on OS object. const RetainSummary *getOSSummaryReleaseRule(const FunctionDecl *FD); + /// Free the OS object. + const RetainSummary *getOSSummaryFreeRule(const FunctionDecl *FD); enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable }; @@ -620,13 +631,36 @@ class RetainSummaryManager { const RetainSummary * generateSummary(const FunctionDecl *FD, bool &AllowAnnotations); + /// Return a summary for OSObject, or nullptr if not found. + const RetainSummary *getSummaryForOSObject(const FunctionDecl *FD, + StringRef FName, QualType RetTy); + + /// Return a summary for Objective-C or CF object, or nullptr if not found. + const RetainSummary *getSummaryForObjCOrCFObject( + const FunctionDecl *FD, + StringRef FName, + QualType RetTy, + const FunctionType *FT, + bool &AllowAnnotations); + + /// Apply the annotation of {@code pd} in function {@code FD} + /// to the resulting summary stored in out-parameter {@code Template}. + /// \return whether an annotation was applied. + bool applyFunctionParamAnnotationEffect(const ParmVarDecl *pd, + unsigned parm_idx, + const FunctionDecl *FD, + ArgEffects::Factory &AF, + RetainSummaryTemplate &Template); + public: RetainSummaryManager(ASTContext &ctx, bool usesARC, - bool trackOSObject) + bool trackObjCAndCFObjects, + bool trackOSObjects) : Ctx(ctx), ARCEnabled(usesARC), - TrackOSObjects(trackOSObject), + TrackObjCAndCFObjects(trackObjCAndCFObjects), + TrackOSObjects(trackOSObjects), AF(BPAlloc), ScratchArgs(AF.getEmptyMap()), ObjCAllocRetE(usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) : RetEffect::MakeOwned(RetEffect::ObjC)), @@ -636,9 +670,19 @@ public: InitializeMethodSummaries(); } - bool canEval(const CallExpr *CE, - const FunctionDecl *FD, - bool &hasTrustedImplementationAnnotation); + enum class BehaviorSummary { + // Function does not return. + NoOp, + + // Function returns the first argument. + Identity, + + // Function either returns zero, or the input parameter. + IdentityOrZero + }; + + Optional<BehaviorSummary> canEval(const CallExpr *CE, const FunctionDecl *FD, + bool &hasTrustedImplementationAnnotation); bool isTrustedReferenceCountImplementation(const FunctionDecl *FD); @@ -693,6 +737,7 @@ public: void updateSummaryFromAnnotations(const RetainSummary *&Summ, const FunctionDecl *FD); + void updateSummaryForCall(const RetainSummary *&Summ, const CallEvent &Call); @@ -700,9 +745,21 @@ public: RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } + /// \return True if the declaration has an attribute {@code T}, + /// AND we are tracking that attribute. False otherwise. + template <class T> + bool hasEnabledAttr(const Decl *D) { + return isAttrEnabled<T>() && D->hasAttr<T>(); + } + + /// Check whether we are tracking properties specified by the attributes. + template <class T> + bool isAttrEnabled(); + friend class RetainSummaryTemplate; }; + // Used to avoid allocating long-term (BPAlloc'd) memory for default retain // summaries. If a function or method looks like it has a default summary, but // it has annotations, the annotations are added to the stack-based template diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h index ba37b7f59a..8fd45bf102 100644 --- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h +++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h @@ -55,6 +55,7 @@ private: void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins); void printEnabledCheckerList(raw_ostream &OS, ArrayRef<std::string> plugins, const AnalyzerOptions &opts); +void printAnalyzerConfigList(raw_ostream &OS); } // end GR namespace |